洛谷 P1879 [USACO06NOV]Corn Fields G(状压DP)

题目链接: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 }
AC代码
原文地址:https://www.cnblogs.com/New-ljx/p/12493571.html