NOIP2019 Emiya家今天的饭
NOIP2019 Emiya家今天的飯
ACM退役選手遠程口胡
csf如今真的是太菜了,最后16分的做法愣是想了一下午
考慮使用容斥方法:
1
采用動態規劃,先求出在無限制情況下,安排kkk種烹飪方法總的方案數.
記dp2[i][j]dp2[i][j]dp2[i][j]表示已經考慮完前iii種烹飪方法,共做了jjj個菜的方案數.
那么顯然,決策分2種情況,用或不用第iii種烹飪方法,用的話就只能選一種主要食材.
dp2[i][j]=dp2[i?1][j]+dp2[i?1][j?1]?(∑t=1ma[i][t])dp2[i][j]=dp2[i-1][j] + dp2[i-1][j-1]*(\sum_{t=1}^m a[i][t])dp2[i][j]=dp2[i?1][j]+dp2[i?1][j?1]?(∑t=1m?a[i][t])
時間復雜度O(n2)O(n^2)O(n2),∑t=1ma[i][t]\sum_{t=1}^m a[i][t]∑t=1m?a[i][t]可以提前維護好.
2
采用動態規劃,計算出那些不合法的方案,并將這些方案減掉.
因為每次只能有一個主要食材不合法.所以對每個主要食材單獨考慮,假設當前ttt食材不合法了.
最樸素的想法是,采用dp1[i][j][k]dp1[i][j][k]dp1[i][j][k]表示考慮完前iii種烹飪方法,已經做了jjj個菜,使用ttt食材的有kkk個的方案數.
那么,決策就是第iii中烹飪方案選不選,選了之后,選不選ttt作為食材,一共333個轉移.
記錄linesum[i]=∑t=1ma[i][t]linesum[i]=\sum_{t=1}^m a[i][t]linesum[i]=∑t=1m?a[i][t]
dp1[i][j][k]=dp1[i?1][j][k]+dp1[i?1][j?1][k?1]?a[i][t]+dp1[i?1][j?1][k]?(linesum[i]?a[i][t])dp1[i][j][k]=dp1[i-1][j][k]+dp1[i-1][j-1][k-1]*a[i][t]+dp1[i-1][j-1][k]*(linesum[i]-a[i][t])dp1[i][j][k]=dp1[i?1][j][k]+dp1[i?1][j?1][k?1]?a[i][t]+dp1[i?1][j?1][k]?(linesum[i]?a[i][t])
最后答案減去dp1[n][j][k]∣k>j/2dp1[n][j][k]|_{k \gt j/2}dp1[n][j][k]∣k>j/2?
時間復雜度為O(n3m)O(n^3m)O(n3m),只能過84分,接下來繼續優化
事實上,我們無需同時記錄jjj和kkk,而只需要記錄k?(j?k)k - (j-k)k?(j?k)的值就足夠了,也就是ttt食材的數量和非ttt食材的數量.
這樣的話,記錄dp1[i][Δ]dp1[i][\Delta]dp1[i][Δ]表示考慮完前iii行,選取的ttt食材和非ttt食材的差值為Δ\DeltaΔ時候,方案數.
轉移方程如下
dp1[i][Δ]=dp1[i?1][Δ]+dp1[i?1][Δ?1]?a[i][t]+dp1[i?1][Δ+1]?(linesum[i]?a[i][t])dp1[i][\Delta]=dp1[i-1][\Delta] + dp1[i-1][\Delta-1]*a[i][t]+dp1[i-1][\Delta+1]*(linesum[i]-a[i][t])dp1[i][Δ]=dp1[i?1][Δ]+dp1[i?1][Δ?1]?a[i][t]+dp1[i?1][Δ+1]?(linesum[i]?a[i][t])
最后答案減去dp1[n][Δ]∣Δ>0dp1[n][\Delta]|_{\Delta>0}dp1[n][Δ]∣Δ>0?
時間復雜度O(n2m)O(n^2m)O(n2m)
綜上,總的時間復雜度O(n2m)O(n^2m)O(n2m)
AC代碼
#include <iostream> #include <cstring> using namespace std; #define int long long const int MOD = 998244353; const int maxn = 107,maxm = 2007; int dp1[maxn][2*maxn]; // int dp2[maxn][maxn]; int linesum[maxn]; //s1表示 int a[maxn][maxm]; int n, m; signed main() {cin >> n >> m;for(int i = 1;i <= n;++i) {for(int j = 1;j <= m;++j) {cin >> a[i][j];a[i][j] %= MOD;linesum[i] = ( linesum[i] + a[i][j] ) % MOD;}}int ans = 0;for(int t = 1;t <= m;++t) {memset(dp1,0,sizeof(dp1));dp1[0][0 + 100] = 1;for(int i = 1;i <= n;++i) {for(int j = -i + 100;j <= i + 100;++j) {dp1[i][j] = dp1[i-1][j];dp1[i][j] += (dp1[i-1][j-1] * a[i][t]) % MOD;//取dp1[i][j] += (dp1[i-1][j+1] * ((linesum[i] - a[i][t] + MOD) % MOD)) % MOD;//不取dp1[i][j] %= MOD;}}for(int j = 1;j <= n;++j) {ans = (ans - dp1[n][j + 100]) % MOD;}}dp2[0][0] = 1;for(int i = 1;i <= n;++i) {for(int j = 0;j <= i;++j) {dp2[i][j] = dp2[i-1][j];for(int k = 1;k <= m;++k) {dp2[i][j] += dp2[i-1][j-1] * a[i][k] % MOD;dp2[i][j] %= MOD;}}}for(int j = 1;j <= n;++j)ans = (ans + dp2[n][j]) % MOD;cout << ans << endl;return 0; }總結
以上是生活随笔為你收集整理的NOIP2019 Emiya家今天的饭的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 图像处理作业 第8次
- 下一篇: 四边形不等式