首页 > 代码库 > CodeForces 489F Special Matrices

CodeForces 489F Special Matrices

题意:

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 510

int 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;
}


CodeForces 489F Special Matrices