标签:方案 ch CSP2019 一半 LL 今天 菜品 Emiya 数量
【CSP2019】Emiya 家今天的饭
题意
题解
显然根据性质最多的菜品不超过总数量的一半,可以考虑补集转化
即计算有一个菜品超过数量一半的方案数,再用总方案数减
总方案数显然可以一个背包搞定(然而我去年就是因为总方案数没求对挂了)
然后考虑求超过一半的方案数
枚举当前哪个菜品是超过一半的
有一个显然的DP:
$ f_{i,j,k} $ 表示当前到第i行最多的菜品选了j个,其余的选了K个的方案数
但是这样会T
考虑能否优化
注意到我们需要的状态并不需要知道菜品的具体数量,只需要要求菜品的相对数量关系
于是可以枚举相对数量关系来压缩一维
#include<bits/stdc++.h> using namespace std; #define LL long long inline LL read() { LL x= 0,f = 1; char ch; do { ch = getchar(); if(ch == '-') f = -1; }while(ch <'0'||ch >'9'); do { x = (x << 3) + (x << 1) + ch - '0'; ch = getchar(); }while(ch >= '0' && ch <= '9'); return f*x; } const int MOD = 998244353; const int MAXN = 100 + 10; const int MAXM = 2000 + 10; int n,m; LL a[MAXN][MAXM]; LL tot_meal; LL f[MAXN],s[MAXN]; LL dp[MAXN][MAXN<<1]; int main() { // freopen("meal.in","r",stdin); // freopen("meal.out","w",stdout); n = read(),m = read(); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { a[i][j] = read(); s[i] += a[i][j];s[i] %= MOD; } } f[0] = 1; for(int i=1;i<=n;i++) for(int j=i;j>=1;j--) f[j] = (f[j] + f[j-1] * s[i] % MOD) % MOD; for(int i=1;i<=n;i++) tot_meal += f[i] ,tot_meal %= MOD; //cout << tot_meal << endl; LL ans = tot_meal; for(register int cur=1;cur<=m;cur++) { memset(dp,0,sizeof(dp)); dp[0][n] = 1; for(int i=1;i<=n;i++) { for(int j=1;j<=n+i;j++) { dp[i][j] = dp[i-1][j] % MOD; (dp[i][j] += dp[i-1][j+1] * (s[i] - a[i][cur])) %= MOD; (dp[i][j] += dp[i-1][j-1] * a[i][cur]) %= MOD; } } for(int j=n+1;j<=2*n;j++) ans = (ans - dp[n][j] + MOD) % MOD; } cout << ans << endl; }
标签:方案,ch,CSP2019,一半,LL,今天,菜品,Emiya,数量 来源: https://www.cnblogs.com/wlzs1432/p/14013262.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。