CodeForces 489F Special Matrices

来源:互联网 发布:电大答题软件 编辑:程序博客网 时间:2024/06/18 11:56

题意:

n(500)*n的矩阵  每行每列只有两个1  现在给出前m行  问  有几种合法的矩阵

思路:

只需要考虑每列上有几个1  然后按行扫描  每次维护行内只有2个1  这样就能构造出合法矩阵

那么我们定义dp[i][j][k]表示扫描到第i行有j列是包含1个1的有k列是包含2个1的  这时500^3数组开不下  于是滚动i

那么对于dp[i][j][k]

如果n-j-k>=2  则可以选择两列分别填1  即转移到dp[i+1][j+2][k]

如果n-j-k>=1&&j>=1 则可以把某个1的列变成2  同时把0的列变成1  即转移到dp[i+1][j][k+1]

如果j>=2 则可以选择两个1变成2  即转移到dp[i+1][j-2][k+2]

代码:

#include<cstdio>#include<iostream>#include<cstring>#include<string>#include<algorithm>#include<map>#include<set>#include<vector>#include<queue>#include<cstdlib>#include<ctime>#include<cmath>#include<bitset>using namespace std;typedef long long LL;#define N 510int n, m, mod;int dp[2][N][N];int num[N];char s[N];void add(int &x, int y) {x += y;if (x >= mod)x -= mod;}int main() {scanf("%d%d%d", &n, &m, &mod);for (int i = 1; i <= m; i++) {scanf("%s", s + 1);for (int j = 1; j <= n; j++) {if (s[j] == '1')num[j]++;}}int j = 0, k = 0;for (int i = 1; i <= n; i++) {if (num[i] == 1)j++;else if (num[i] == 2)k++;}dp[m & 1][j][k] = 1;for (int i = m + 1; i <= n; i++) {memset(dp[i & 1], 0, sizeof(dp[i & 1]));for (j = 0; j <= n; j++) {for (k = 0; k + j <= n; k++) {if (dp[(i & 1) ^ 1][j][k]) {int zero = n - j - k, one = j, two = k;LL key = dp[(i & 1) ^ 1][j][k];if (zero >= 2)add(dp[i & 1][one + 2][two],(LL) (zero) * (zero - 1) / 2 % mod * key % mod);if (zero >= 1 && one >= 1)add(dp[i & 1][one][two + 1],key * zero % mod * one % mod);if (one >= 2)add(dp[i & 1][one - 2][two + 2],(LL) (one) * (one - 1) / 2 % mod * key % mod);}}}}printf("%d\n", dp[n & 1][0][n]);return 0;}


1 0