4 条题解

  • 0
    @ 2025-3-19 16:09:06

    首先注意到每次只能操作长度为 22 的整数次幂的块,所以说假设我们排序的方案是从块长小的到块长大的来做的话,长块内的元素必须是已经排好序的,才能保证最后的序列是有序的。

    那么我们提出一个引理:单次交换两个长度为 2i12^{i-1} 的块,至多使两个长度为 2i2^i 的块从无序变成有序。

    这个证明是显然的,由于这交换的两个长为 2i12^{i-1} 的块要么处于同一个长度为 2i2^i 的块中,要么分别处于两个不同的长为 2i2^i 的块中,交换至多改变两个长为 2i2^i 的块,所以显然成立。

    于是我们就有一个可以判断无解的方法,扫一遍整个序列,如果出现了超过两个无序的长为 2i2^i 的块,那么必然无法使最后的序列变得有序。

    然后我们继续思考,假设我现在已经得到了一个合法的操作序列,那么先进行交换长块的操作并不会影响小块的有序性,所以我们可以再提出一个引理:如果某个操作序列合法,则该操作序列的全排列都合法。

    假设我们已知某个操作序列交换了 xx 次,则答案会累加 Axx=x!A_x^x=x! 次。

    这时我们又注意到,对于一次交换,至多只有两种可能使得交换合法,这一点你只需要枚举一下序列长度为 44 的时候的所有情况就能证明了,于是,对于所有的 nn 种操作,至多有 2n2^n 种合法的操作序列。

    然后我们惊人的发现 2n2^n 是可以直接爆搜出来的,于是你就切掉了这一题。

    最后我们做一下时间复杂度分析,第 ii 种操作至多会被搜到 2i12^{i-1} 次,进行第 ii 次操作需要把长度为 2ni+12^{n-i+1} 的序列扫一次,于是我们搜索的时间复杂度就为:

    $$O\left(\sum_{i=1}^n2^{i-1}\times 2^{n-i+1}\right)=O(n2^n) $$

    在本题的数据范围下跑的飞快。

    代码

    #include <iostream>
    #include <algorithm>
    #define ll long long
    #define IT int
    using namespace std;
    const ll N=(1LL<<12)+1;
    ll ans;
    IT a[13][N],n;
    void solve(ll step,ll x);
    inline void nxt(ll step,ll x,ll ps1,ll ps2,ll sp1,ll sp2){
    	if(a[step][ps1]+1==a[step][ps2]&&a[step][sp1]+1==a[step][sp2]){
    		a[step+1][ps2>>1]=(a[step][ps2]>>1);
    		a[step+1][sp2>>1]=(a[step][sp2]>>1);
    		solve(step+1,x+1);
    	}
    }
    void solve(ll step,ll x){
    	if(step==n){
    		ll ret=1;
    		for(ll i=2;i<=x;i++) ret*=i;
    		ans+=ret;
    		return;
    	}
    	ll al=(1LL<<(n-step)),cnt=0,apos=-1,bpos=-1;
    	for(ll i=1;i<=al;i+=2){
    		if(a[step][i]+1==a[step][i+1]&&(a[step][i]&1)) a[step+1][(i+1)>>1]=(a[step][i+1]>>1);
    		else{
    			cnt++;
    			if(apos==-1) apos=i;
    			else bpos=i;
    		}
    	}
    	if(cnt>2) return;
    	if(cnt==2){
    		IT ps1=apos,ps2=apos+1;
    		IT sp1=bpos,sp2=bpos+1;
    		
    		swap(a[step][ps1],a[step][sp1]);
    		nxt(step,x,ps1,ps2,sp1,sp2);
    		swap(a[step][ps1],a[step][sp1]);
    		
    		swap(a[step][ps1],a[step][sp2]);
    		nxt(step,x,ps1,ps2,sp1,sp2);
    		swap(a[step][ps1],a[step][sp2]);
    		
    		swap(a[step][ps2],a[step][sp1]);
    		nxt(step,x,ps1,ps2,sp1,sp2);
    		swap(a[step][ps2],a[step][sp1]);
    		
    		swap(a[step][ps2],a[step][sp2]);
    		nxt(step,x,ps1,ps2,sp1,sp2);
    		swap(a[step][ps2],a[step][sp2]);
    	}
    	if(cnt==1){
    		a[step+1][(apos+1)>>1]=(a[step][apos]>>1);
    		solve(step+1,x+1);
    	}
    	if(!cnt) solve(step+1,x);
    }
    int main(){
    	ios::sync_with_stdio(false);
    	cin.tie(0),cout.tie(0);
    	cin>>n;
    	for(ll i=1;i<=(1LL<<n);i++) cin>>a[0][i];
    	solve(0,0);
    	cout<<ans;
    	return 0;
    } 
    

    信息

    ID
    92
    时间
    1000ms
    内存
    256MiB
    难度
    7
    标签
    (无)
    递交数
    34
    已通过
    9
    上传者