[CSP-S2019] Emiya 家今天的饭

题解

P5664
这道题非常水,段誉初二就切了,但是我初中 DP 学的非常差,基本什么都不会,见到的小套路能会一个算一个吧。
直接计算比较困难,尝试使用 DP 求出不合法的方案数即可。
令 sum[i]=j=1na[i][j]
不难发现总方案数很好求,为 Πi=1n(sum[i]+1)1
枚举不合法的列 j,设 dp[i][k] 表示前 i 行选 k 个 j 的点个数与其他列的点个数之差。
可以得到 dp[i][k]=dp[i1][k]+dp[i1][k1]a[i][j]+dp[i1][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 @   StranGePants  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
历史上的今天:
2022-02-13 CDQ 维护斜率优化DP
点击右上角即可分享
微信分享提示