2019 CCF CSP-S2.Emiya 家今天的饭
题目
1155. Emiya 家今天的饭
思路
容斥原理,
d
p
+
d
p
dp + dp
dp+dp, 不是
d
p
o
f
d
p
dp \,of \, dp
dpofdp
核心方法总得方案数减去不合法的方案数, 首先考虑前两个约束, 状态表示
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示前
i
i
i个烹饪方法,使用了
j
j
j个食材的所有方案, 类似于背包问题预处理
f[0][0] = 1;
for (int i = 1; i <= n; ++i) {
for (int j = 0; j <= i; ++j) {
f[i][j] = f[i - 1][j];
if (j) f[i][j] = (f[i][j] + (LL) f[i - 1][j - 1] * s[i] % MOD) % MOD;
}
}
int res = 0;
for (int i = 1; i <= n; ++i) res = (res + f[n][i]) % MOD;
再进行
d
p
dp
dp, 定义
g
[
i
]
[
d
]
g[i][d]
g[i][d]为考虑前
i
i
i个烹饪方式, 对于第
k
k
k个食材, 第
k
k
k个食材出现的次数减去其他食材出现的次数为
d
d
d的所有方案
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long LL;
const int N = 110, M = 2010, MOD = 998244353;
int n, m;
LL w[N][M], s[N];
// f[i][j]前i个烹饪方式, 使用了j个食材的所有方案, g[i][d]表示前i个烹饪方式对于食材k来说所有菜中k出现的次数减去其他食材出现的次数是d的所有方案
int f[N][M], g[N][N << 1];
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
cin >> w[i][j];
s[i] = ((LL) s[i] + w[i][j]) % MOD;
}
}
f[0][0] = 1;
for (int i = 1; i <= n; ++i) {
for (int j = 0; j <= i; ++j) {
f[i][j] = f[i - 1][j];
if (j) f[i][j] = (f[i][j] + (LL) f[i - 1][j - 1] * s[i] % MOD) % MOD;
}
}
int res = 0;
for (int i = 1; i <= n; ++i) res = (res + f[n][i]) % MOD;
for (int k = 1; k <= m; ++k) {
memset(g, 0, sizeof g);
g[0][N] = 1;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j + 1 < 2 * N; ++j) {
// 不选择当前烹饪方法
g[i][j] = g[i - 1][j];
// 选择食材k
g[i][j] = (g[i - 1][j] + (LL) g[i - 1][j - 1] * w[i][k]) % MOD;
// 不选择食材k
g[i][j] = (g[i][j] + (LL) g[i - 1][j + 1] * (s[i] - w[i][k])) % MOD;
}
}
for (int i = 1; i <= n; ++i) res = (res - g[n][N + i]) % MOD;
}
cout << (res + MOD) % MOD << "\n";
return 0;
}