4 条题解
-
0
首先注意到每次只能操作长度为 的整数次幂的块,所以说假设我们排序的方案是从块长小的到块长大的来做的话,长块内的元素必须是已经排好序的,才能保证最后的序列是有序的。
那么我们提出一个引理:单次交换两个长度为 的块,至多使两个长度为 的块从无序变成有序。
这个证明是显然的,由于这交换的两个长为 的块要么处于同一个长度为 的块中,要么分别处于两个不同的长为 的块中,交换至多改变两个长为 的块,所以显然成立。
于是我们就有一个可以判断无解的方法,扫一遍整个序列,如果出现了超过两个无序的长为 的块,那么必然无法使最后的序列变得有序。
然后我们继续思考,假设我现在已经得到了一个合法的操作序列,那么先进行交换长块的操作并不会影响小块的有序性,所以我们可以再提出一个引理:如果某个操作序列合法,则该操作序列的全排列都合法。
假设我们已知某个操作序列交换了 次,则答案会累加 次。
这时我们又注意到,对于一次交换,至多只有两种可能使得交换合法,这一点你只需要枚举一下序列长度为 的时候的所有情况就能证明了,于是,对于所有的 种操作,至多有 种合法的操作序列。
然后我们惊人的发现 是可以直接爆搜出来的,于是你就切掉了这一题。
最后我们做一下时间复杂度分析,第 种操作至多会被搜到 次,进行第 次操作需要把长度为 的序列扫一次,于是我们搜索的时间复杂度就为:
$$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
- 上传者