社区讨论
28pts求助
P5664[CSP-S 2019] Emiya 家今天的饭参与者 2已保存回复 4
讨论操作
快速查看讨论及其快照的属性,并进行相关操作。
- 当前回复
- 4 条
- 当前快照
- 1 份
- 快照标识符
- @m2lc55y1
- 此快照首次捕获于
- 2024/10/23 11:49 去年
- 此快照最后确认于
- 2025/11/04 16:28 4 个月前
只过了前六个点
CPP#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const long long mod=998244353;
int n,m;
long long a[105][2005];
long long sum[105];
long long f[105][5005];
/*
定义f[i][j][k]为前i行选了超限列j个,不超限列k个,有转移方程:(设超限列号为l)
f[i][j][k]=f[i-1][j][k]+a[i][l]*f[i-1][j-1][k]+(sum[i]-a[i][l])*f[i-1][j][k-1]
即不选这一行+选这一行的超限列(注意每个位置有多个可选,要乘数量)+选这一行的不超限列
考虑优化状态,因为发现j,k是相关的
重定义f[i][j]为前i行选了(超限列-不超限列)=j个,前i行一共选i个
由于最多选超限列i个,故j<=i
不能直接在递推里限制j>0,这一行超限不代表上一行不超限
所以j∈[-i,i],i∈[1,n],不能出现负数下标,所以令t=j+n∈[0,2n],其中t>n符合要求
f[i][t]=f[i-1][t]+a[i][l]*f[i-1][t-1]+(sum[i]-a[i][l])*f[i-1][t+1] //减一加一别搞混了,这是逆向考虑的
*/
long long S=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]);
sum[i]+=a[i][j]%mod,sum[i]%=mod;
}
S*=(sum[i]+1)%mod,S%=mod;
}
S--; //总方案数一定别忘了排除什么也不选的情况!!!
long long cnt=0;
for(int l=1;l<=m;l++) //枚举每一列为超限列
{
memset(f,0,sizeof(f));
f[0][n]=1;
for(int i=1;i<=n;i++)
for(int t=n-i;t<=n+i;t++)
f[i][t]=f[i-1][t]%mod+(a[i][l]%mod)*(f[i-1][t-1]%mod)+((sum[i]%mod-a[i][l]%mod)%mod)*f[i-1][t+1]%mod,f[i][t]%=mod;
for(int t=n+1;t<=n+n;t++) cnt+=f[n][t]%mod,cnt%=mod; //只有这些是符合要求的
}
printf("%lld",(S%mod-cnt%mod)%mod);
}
回复
共 4 条回复,欢迎继续交流。
正在加载回复...