【bzoj3990】 SDOI2015排序 dfs搜索+剪枝

来源:互联网 发布:淘宝运营报价 编辑:程序博客网 时间:2024/06/06 14:27

航爷出的题果然太耗脑子了,看完gty大哥的题解才会做。首先有一个结论,操作序列的顺序不影响最终结果,所以我们搜出一种合法的操作组合之后乘以步骤数的阶乘就可以了。然后我们发现,从小到大搜索,当第i次操作完成后,每一个2^i的段必须变成有序的,而且每次操作只允许有4个顺序不同的,这样一交换才可能变成有序。


#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<iostream>#include<algorithm>#define maxn 10010using namespace std;int n;int a[maxn];long long c[13];long long ans;void swap(int i,int j,int len){for (int k=1;k<=len;k++) swap(a[i+k-1],a[j+k-1]);}bool check(int k){for (int i=1;i<=(1<<(n-k));i++)  if (a[(i-1)*(1<<k)+1]+(1<<(k-1))!=a[(i-1)*(1<<k)+1+(1<<(k-1))]) return 0;return 1;}void dfs(int now,int num){if (now && !check(now)) return;if (now==n) {ans+=c[num];return;}dfs(now+1,num);int tmp[5],tot=0;for (int i=1;i<=(1<<(n-(now+1)+1));i+=2)  if (a[i*(1<<now)+1]!=a[(i-1)*(1<<now)+1]+(1<<now))  {      if (tot==4) return;        else tmp[++tot]=i,tmp[++tot]=i+1;  }if (!tot)  return;for (int i=1;i<tot;i++)  for (int j=i+1;j<=tot;j++)    {    swap((1<<now)*(tmp[i]-1)+1,(1<<now)*(tmp[j]-1)+1,(1<<now));    dfs(now+1,num+1);    swap((1<<now)*(tmp[i]-1)+1,(1<<now)*(tmp[j]-1)+1,(1<<now));    }}int main(){c[0]=1;for (int i=1;i<=12;i++) c[i]=c[i-1]*i;scanf("%d",&n);for (int i=1;i<=(1<<n);i++) scanf("%d",&a[i]);dfs(0,0);printf("%lld\n",ans);return 0;}


0 0