首先统计一下前m行中,有x列1的个数为0,有y列1的个数为1.
设d(i, j)表示有i列1的个数为0,有j列1的个数为1,能到达这个状态的矩阵的个数。
则d(x, y) = 1
每一行都是两个1一起放,枚举这两个1分别放在了哪种列上面
于是有状态转移:
- d(i - 2, j + 2) += d(i, j) * C(i, 2)
- d(i - 1, j) += d(i, j) * i * j
- d(i, j - 2) += d(i, j) * C(j, 2)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 7 const int maxn = 500 + 10; 8 9 int n, m; 10 11 long long d[maxn][maxn], MOD; 12 13 char s[maxn]; 14 int cnt[maxn]; 15 16 int main() 17 { 18 scanf("%d%d%I64d", &n, &m, &MOD); 19 for(int i = 0; i < m; i++) 20 { 21 scanf("%s", s); 22 for(int j = 0; j < n; j++) if(s[j] == '1') cnt[j]++; 23 } 24 25 int zero = 0, ones = 0; 26 for(int i = 0; i < n; i++) if(!cnt[i]) zero++; else if(cnt[i] == 1) ones++; 27 28 d[zero][ones] = 1; 29 for(int i = n; i >= 0; i--) 30 for(int j = n; j >= 0; j--) 31 { 32 if(i >= 2) d[i-2][j+2] = (d[i-2][j+2] + d[i][j] * i * (i - 1) / 2) % MOD; 33 if(i && j) d[i-1][j] = (d[i-1][j] + d[i][j] * i * j) % MOD; 34 if(j >= 2) d[i][j-2] = (d[i][j-2] + d[i][j] * j * (j - 1) / 2) % MOD; 35 } 36 37 printf("%I64d ", d[0][0]); 38 39 return 0; 40 }