P5664 [CSP-S2019] Emiya 家今天的饭
n行m列的矩阵 ai 选 k 个数 每行选<=1 每列<=[k/2] 问有多少种方法
》dp 但是dp过程难以控制 “每行选<=1 每列<=[k/2]” 尤其是 每列<=[k/2] -> 所以考虑容斥
》不合法的行只需要 每次取<=1 列的话 最多只有一列因为<=k/2->枚举不合法的列
> g[][]->前i(1~n)行 选 j(0~n)个数字 的 所有合法的方案
1.选/不选->g[i][j]=max(g[i-1][j],g[i-1][j-1]+sum[i])
g[0][0]=1
> f[i][j][k] 枚举col行不合法 前i(1~n)行 col 列选j 个 其他选k
选(col、其他)、不选 ->f[i][j][k]=max(f[i-1][j][k],a[col]*f[i][j-1][k]+(sum[i]-a[col])*f[i-1][j][k-1])
O(mn^3)
>优化 [j][k] 相对关系 ->f[i][j]前i行 col列 比其他列 多 j(-n~n)个数 O(mn^2)
f[i][j] = (f[i-1][j]+f[i-1][j-1]*a[i][col]%mod+f[i-1][j+1]*sum[i][col]%mod)%mod;
f[0][n]=1
#include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> #define mod 998244353 using namespace std; typedef long long ll; const int MAXN = 105, MAXM = 2005; int n,m,a[MAXN][MAXM],sum[MAXN][MAXM]; ll f[MAXN][MAXN*2],g[MAXN][MAXN]; int main() { cin >> n >> m; for(int i = 1; i<=n; i++) for(int j = 1; j<=m; j++) { scanf("%d",&a[i][j]); sum[i][0] = (sum[i][0]+a[i][j])%mod; } for(int i = 1; i<=n; i++) for(int j = 1; j<=m; j++) sum[i][j] = (sum[i][0]-a[i][j]+mod)%mod; ll ans = 0; for(int col = 1; col<=m; col++) { memset(f,0,sizeof(f)); f[0][n] = 1; for(int i = 1; i<=n; i++) for(int j = n-i; j<=n+i; j++) f[i][j] = (f[i-1][j]+f[i-1][j-1]*a[i][col]%mod+f[i-1][j+1]*sum[i][col]%mod)%mod; for(int j = 1; j<=n; j++) ans = (ans+f[n][n+j])%mod; } g[0][0] = 1; for(int i = 1; i<=n; i++) for(int j = 0; j<=n; j++) g[i][j] = (g[i-1][j]+(j>0?g[i-1][j-1]*sum[i][0]%mod:0))%mod; for(int j = 1; j<=n; j++) ans = (ans-g[n][j]+mod)%mod; cout << ans*(mod-1)%mod << endl; return 0; }

浙公网安备 33010602011771号