[CSP-S2019] Emiya 家今天的饭

题解

P5664
这道题非常水,段誉初二就切了,但是我初中 DP 学的非常差,基本什么都不会,见到的小套路能会一个算一个吧。
直接计算比较困难,尝试使用 DP 求出不合法的方案数即可。
令 sum[i]=\(\sum_{j=1}^na[i][j]\)
不难发现总方案数很好求,为 \(\Pi_{i=1}^n(sum[i]+1)-1\)
枚举不合法的列 j,设 dp[i][k] 表示前 i 行选 k 个 j 的点个数与其他列的点个数之差。
可以得到 \(dp[i][k]=dp[i-1][k]+dp[i-1][k-1]*a[i][j]+dp[i-1][k+1]*(sum[i]-a[i][j])\)
因为下标可能为负,所以整体加 n 即可。
code:

#include<cstdio>
#include<iostream>
using namespace std;
const int MAXN=105;
const int MAXM=2005;
const int Mod=998244353;
#define ll long long
int n,m;
ll a[MAXN][MAXM],dp[MAXN][MAXN<<1],sum[MAXN][MAXM],Ans=1;
int main(){
	scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){scanf("%lld",&a[i][j]);}}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;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)%Mod;
	}
	for(int i=1;i<=n;i++){
		if(!sum[i][0]) continue;Ans=Ans*(sum[i][0]+1)%Mod;
	}
	Ans--;
	for(int i=1;i<=m;i++){for(int j=0;j<=n;j++){for(int k=0;k<=2*n;k++){dp[j][k]=0;}}
		dp[0][n]=1;
		for(int j=1;j<=n;j++){for(int k=n-j;k<=n+j;k++){dp[j][k]=(dp[j-1][k]+dp[j-1][k-1]*a[j][i]%Mod+dp[j-1][k+1]*sum[j][i]%Mod)%Mod;}}
		for(int j=1;j<=n;j++) Ans=(((Ans-dp[n][j+n])%Mod)+Mod)%Mod;
	}
	printf("%lld",Ans);return 0;
}
posted @ 2023-02-13 22:09  StranGePants  阅读(7)  评论(0编辑  收藏  举报