题目描述:
语死早,描述不出来TAT.
题目分析:
对于任何一个操作序列,操作顺序不影响最后结果
所以当K次操作可以成功的时候 贡献即为 K!
我们从小到大DFS,对于第i次操作我们将序列分成
2n−i
2
n
−
i
段,每段长度
2i
2
i
我$们找到序列中不是连续递增的段,如果这样的段超过2个,显然这种情况无法使之合法
如果没有这样的段,就不需要执行这个操作
如果有一个这样的段,判断将这个段的前半部分和后半部分交换后是否连续递增,如果是就交换然后继续DFS
如果有两个这样的段,判断四种交换情况然后DFS
题目链接:
Ac 代码:
#include <cstdio>
#include <iostream>
#define ll long long
#define maxm 1<<13
#define il inline
ll num[15],ans;
int a[maxm],bix[15],n;
il bool check(int x,int k)
{
for(int i=1;i<bix[k];i++) if(a[x+i]!=a[x+i-1]+1)return 0;
return 1;
}
il void swap(int x,int y,int k)
{
for(int i=0;i<bix[k];i++) std::swap(a[x+i],a[y+i]);
}
void dfs(int now,int k)
{
//printf("%d %d\n",now,k);
if(now==n+1)
{
ans+=num[k];
return;
}
int c1=0,c2=0;
for(int i=1;i<=bix[n];i+=bix[now])
if(!check(i,now))
{
if(!c1) c1=i;
else
{
if(!c2) c2=i;
else return;
}
}
if(!c1&&!c2)
dfs(now+1,k);
else
{
if(c1&&!c2)
{
swap(c1,c1+bix[now-1],now-1);
dfs(now+1,k+1);
swap(c1,c1+bix[now-1],now-1);
}
else
{
for(int x=0;x<=1;x++)
for(int y=0;y<=1;y++)
{
swap(c1+x*bix[now-1],c2+y*bix[now-1],now-1);
if(check(c1,now)&&check(c2,now))
{
dfs(now+1,k+1);
swap(c1+x*bix[now-1],c2+y*bix[now-1],now-1);
break;
}
swap(c1+x*bix[now-1],c2+y*bix[now-1],now-1);
}
}
}
}
int main()
{
scanf("%d",&n);
num[0]=1;
for(int i=1;i<=12;i++) num[i]=num[i-1]*i;
bix[0]=1;
for(int i=1;i<=12;i++) bix[i]=bix[i-1]<<1;
for(int i=1;i<=bix[n];i++) scanf("%d",a+i);
dfs(0,0);
printf("%lld\n",ans);
return 0;
}