题解 AT2669【[AGC017F] Zigzag】
xtx1092515503 · · 题解
可以通过的暴力做法。
令
考虑某一条折线。我们要计算 其下方所有折线的
/\
/\ / \ /
/ \ / \/\/
\/
123456789ABCDEFG
如上图所示的一条折线。则,其有如下几个后继态:
- 把
(2,3) 对应的“角”扳成\/的样式。也即,1234的状态变成/\/\。 - 把
(9,A) 扳下去。 - 把
(D,E) 扳下去。 - 把
G 扳下去。
我们考虑容斥。则
暴力枚举哪些角被扳下去。一个角在
口胡一下复杂度:一个有
但是分析理论复杂度没啥用处(其实是这个家伙不会分析)。实测
代码:
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
void ADD(int&x,int y){if((x+=y)>=mod)x-=mod;}
int n,m,K,m0[30],m1[30],f[1<<20],res,pc[1<<20];
int main(){
scanf("%d%d%d",&n,&m,&K),n--;
for(int i=1,x,y,z;i<=K;i++)
scanf("%d%d%d",&x,&y,&z),(z==1?m1:m0)[x]|=1<<n-y;
for(int i=1;i<(1<<n);i++)pc[i]=pc[i>>1]+(i&1);
for(int i=0;i<(1<<n);i++)
if((i&m1[1])==m1[1]&&!(i&m0[1]))f[i]=1;
// for(int i=0;i<(1<<n);i++)printf("%d ",f[i]);puts("");
for(int _=2;_<=m;_++){
for(int j=0;j<(1<<n);j++){
int U=0;
if(j&1)U|=1;
for(int i=1;i<n;i++)if((j&(1<<i))&&!(j&(1<<i-1)))
U|=1<<i;
for(int u=U;u;u=(u-1)&U){
int v=(u|u>>1)&((1<<n)-1);
if(pc[u]&1)ADD(f[j],f[j^v]);
else ADD(f[j],mod-f[j^v]);
}
}
for(int j=0;j<(1<<n);j++)if((j&m1[_])!=m1[_]||(j&m0[_]))f[j]=0;
}
// for(int i=0;i<(1<<n);i++)printf("%d ",f[i]);puts("");
for(int i=0;i<(1<<n);i++)(res+=f[i])%=mod;
printf("%d\n",res);
return 0;
}