[BZOJ4000][TJOI2015]棋盘(状压DP+矩阵快速幂)
2018-10-29 14:52
288 查看
题意极其有毒,注意给的行列都是从0开始的。
状压DP,f[i][S]表示第i行状态为S的方案数,枚举上一行的状态转移。$O(n2^{2m})$
使用矩阵加速,先构造矩阵a[S1][S2]表示上一行为S1是下一行是否能为S2,快速幂加速后得解。$O(2^{3m}m^2+2^{3m}\log n)$
#include<cstdio> #include<cstring> #include<algorithm> #define rep(i,l,r) for (int i=(l); i<=(r); i++) typedef unsigned int ul; using namespace std; const int N=70; ul ans; int n,m,p,k,ed,x,tot; struct P{ int x,y; }d[110]; struct Mat{ ul a ; ul* operator [](int x){ return a[x]; } Mat (){ memset(a,0,sizeof(a)); } }a,res; Mat mul(Mat a,Mat b){ Mat c; rep(i,0,ed) rep(j,0,ed) rep(k,0,ed) c[i][k]+=a[i][j]*b[j][k]; return c; } Mat ksm(Mat a,int b){ Mat res; rep(i,0,ed) res[i][i]=1; for (; b; a=mul(a,a),b>>=1) if (b & 1) res=mul(res,a); return res; } int main(){ freopen("bzoj4000.in","r",stdin); freopen("bzoj4000.out","w",stdout); scanf("%d%d%d%d",&n,&m,&p,&k); k++; ed=(1<<m)-1; rep(i,1,3) rep(j,1,p){ scanf("%d",&x); if (x) d[++tot]=(P){i-2,j-k}; } rep(S1,0,ed) rep(S2,0,ed){ bool flag=0; rep(i,0,m-1) if (S1&(1<<i)) rep(j,0,m-1) if (S2&(1<<j)) rep(k,1,tot) if ((d[k].x==1 && d[k].y==j-i) || (d[k].x==-1 && d[k].y==i-j)) { flag=1; break; } rep(i,0,m-2) if (S2&(1<<i)) rep(j,i+1,m-1) if (S2&(1<<j)) rep(k,1,tot) if (d[k].x==0 && (d[k].y==j-i || d[k].y==i-j)) { flag=1; break; } a[S1][S2]=!flag; } res[0][0]=1; res=mul(res,ksm(a,n)); rep(i,0,ed) ans+=res[0][i]; printf("%u\n",ans); return 0; }
相关文章推荐
- BZOJ4000 TJOI2015棋盘(状压dp+矩阵快速幂)
- BZOJ 4000: [TJOI2015]棋盘( 状压dp + 矩阵快速幂 )
- 【bzoj4000】[TJOI2015]棋盘 dp+矩乘
- bzoj 4000 [TJOI2015]棋盘 dp 矩乘
- bzoj 4000: [TJOI2015]棋盘
- 【BZOJ4000】 [TJOI2015]棋盘
- BZOJ4000 [TJOI2015]棋盘 【状压dp + 矩阵优化】
- BZOJ4000 [TJOI2015]棋盘
- BZOJ4000: [TJOI2015]棋盘 解题报告
- 4000: [TJOI2015]棋盘
- [BZOJ3998] [TJOI2015] 弦论 - 后缀自动机
- [BZOJ3998][TJOI2015]弦论-后缀树
- bzoj3998 TJOI2015 弦论
- bzoj 3998: [TJOI2015]弦论 后缀自动机
- BZOJ 3998: [TJOI2015]弦论
- [BZOJ3998][TJOI2015]弦论(后缀自动机)
- 【bzoj3998】[TJOI2015]弦论 后缀自动机+dp
- [BZOJ 3996] [TJOI 2015] 线性代数
- BZOJ3998 [TJOI2015]弦论 【后缀自动机】
- 【BZOJ3997】【TJOI2015】组合数学 Dilworth定理 DP