[USACO06NOV]Corn Fields G
洛谷AC通道!
一看题目,肯定就是状态压缩的题目。
设$f_{i,k}$表示: 在第$i$行的时候,二进制状态$k$下的方案数量。
首先,我们要保证一个状态下在自己那一行是合法的,那么用$g_i$记录状态$i$是否合法。
继续,我们还要保证上下两行不能有相邻的边,即$(j$ & $k) == 0$, 保证所有的$1,0$全部错开。
如果都合法,那我们直接把状态累计的数量加起来就ok啦!
#includeusing namespace std; #define N ((1<<12)+10) const int mod = (int)1e8; template <class T> inline void read(T& a){ T x = 0, s = 1; char c = getchar(); while(!isdigit(c)){ if(c == '-') s = -1; c = getchar(); } while(isdigit(c)){ x = x * 10 + (c ^ '0'); c = getchar(); } a = x * s; return ; } int F[N]; // 记录每一行的所有状态 int g[N]; // 记录这种状态是否合法 int dp[13][N], a[N][N]; int n, m; int main(){ read(m), read(n); for(int i = 1; i <= m; i++) for(int j = 1; j <= n; j++){ read(a[i][j]); F[i] = (F[i] << 1) + a[i][j]; // 保存每一行的状态 } for(int i = 0; i < (1 << n); i++) g[i] = (!(i & (i << 1))) && (!(i & (i >> 1))); // g[i] 保证 i 这一状态合法(所有行通用) dp[0][0] = 1; for(int i = 1; i <= m; i++){ for(int j = 0; j < (1 << n); j++){ if(g[j] && ((j & F[i]) == j)){ // 保证在肥沃的草地上 for(int k = 0; k < (1 << n); k++){ if((k & j) == 0) // 保证上一行和这一行没有公共边 dp[i][j] = (dp[i][j] + dp[i-1][k]) % mod; // 累加 } } } } int ans = 0; for(int i = 0; i < (1 << n); i++) ans = (ans + dp[m][i]) % mod; // 最后一行所有的状态的总和 cout << ans << endl; return 0; }