P5664 [CSP-S2019] Emiya 家今天的饭 题解

题目链接: P5664 [CSP-S2019] Emiya 家今天的饭

思路:

显然可以算出总数减去不合法的,不合法即有一列超过一半,显然最多一列,枚举这一列。

考虑 dp,设 \(f(i,j,k)\) 表示前 \(i\) 个方法,\(j\) 个这一列,\(k\) 个其他列。

但是这样是 \(O(n^3m)\),我们需要优化。

显然我们只关心 \(j,k\) 相对大小,直接差值 dp 即可。

点击查看代码
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 105;
const int M = 2005;
const int mod = 998244353;

int n, m;
int a[N][M] = {{0}};
int s[N] = {0};

void add(int &x, int y) {
	x = (x + y) % mod;
}

int f[N][N * 2] = {{0}};
int cal(int x) {
	f[0][n] = 1;
	for (int i = 1; i <= n; i++) {
		for (int j = 0; j <= n * 2; j++) {
			f[i][j] = 0;
			add(f[i][j], f[i - 1][j]);
			if (j > 0)
				add(f[i][j], 1ll * a[i][x] * f[i - 1][j - 1] % mod);
			if (j < n * 2)
				add(f[i][j], 1ll * (s[i] - a[i][x] + mod) % mod * f[i - 1][j + 1] % mod);
		}
	}
	int ans = 0;
	for (int i = n + 1; i <= n * 2; i++)
		add(ans, f[n][i]);
	return ans;
}

int main() {
	cin >> n >> m;
	int ans = 1;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			cin >> a[i][j];
			add(s[i], a[i][j]);
		}
		ans = 1ll * ans * (s[i] + 1) % mod;
	}
	ans = (ans - 1 + mod) % mod;
	for (int j = 1; j <= m; j++)
		ans = (ans - cal(j) + mod) % mod;
	cout << ans << endl;
	return 0;
}
posted @ 2024-03-21 20:26  rlc202204  阅读(11)  评论(0编辑  收藏  举报