题目链接:https://www.luogu.com.cn/problem/P1879
这道题有些神奇。
首先我们把每一行都压缩成一个二进制数,然后我们考虑在某一块土地上是否种草,是否种草则让j从0~maxstate进行枚举。
只有一种情况是不符合题意的:土地为0,而种草为1。那么即(j&f[i]!=j)就为这种情况。
根据1&1=1,0&1=0,1&0=0,0&0=0。 设x&y=z,那么我们可以发现一个规律,只有当x=0,y=1时,y不等于z。 即可以证明(j&f[i]))!=j的正确性。
其他的就按一个基本的状压DP来即可。
dp[][]:第一维为行数,第二维为状态。
AC代码:
1 #include<cstdio> 2 #include<iostream> 3 using namespace std; 4 typedef long long ll; 5 const ll mod=1e9; 6 ll dp[20][4100]; 7 int f[4100]; 8 int state[4100]; 9 int main(){ 10 int m,n; 11 scanf("%d%d",&m,&n); 12 int maxstate=(1<<n); 13 for(int i=1;i<=m;i++){ 14 for(int j=1;j<=n;j++){ 15 int x; 16 scanf("%d",&x); 17 f[i]=(f[i]<<1)+x; 18 } 19 } 20 for(int i=0;i<maxstate;i++) state[i]=((i&(i<<1))==0&&(i&(i>>1))==0); 21 dp[0][0]=1; 22 for(int i=1;i<=m;i++){ 23 for(int j=0;j<maxstate;j++){ 24 if(state[j]==0||((j&f[i]))!=j) continue;//太神奇了 25 for(int k=0;k<maxstate;k++) if((j&k)==0) dp[i][j]=(dp[i][j]+dp[i-1][k])%mod; 26 } 27 } 28 ll ans=0; 29 for(int i=0;i<maxstate;i++){ 30 ans+=dp[m][i]; 31 ans%=mod; 32 } 33 printf("%lld ",ans); 34 return 0; 35 }