loj2538 「PKUWC2018」Slay the Spire 【dp】
題目鏈接
loj2538
題解
比較明顯的是,由于強化牌倍數大于\(1\),肯定是能用強化牌盡量用強化牌
如果強化牌大于等于\(k\),就留一個位給攻擊牌
所以我們將兩種牌分別排序,企圖計算\(F(i,j)\)表示\(i\)張強化牌選出最強的\(j\)張的所有方案的倍數和
\(G(i,j)\)表示從\(i\)張攻擊牌選出最強\(j\)張的所有方案的傷害和
那么
\[ans = \sum\limits_{i = 0}^{k - 1} F(i,i)G(m - i,k - i) + \sum\limits_{i = k}^{m} F(i,k - 1)G(m - i,1)\]
所以我們只需計算出\(F\)和\(G\)
以\(F\)為例,我們枚舉選出最后一張牌是什么
那么設\(f[i][j]\)表示用了\(i\)張強化牌,最后一張是\(j\)的倍數和
同樣設\(g[i][j]\)表示用了\(i\)張攻擊牌,最后一張是\(j\)的傷害和
那么有
\[f[i][j] = w_j\sum\limits_{x = 0}^{j - 1}f[i - 1][x]\]
\[g[i][j] = w_j{j - 1 \choose i - 1} + \sum\limits_{x = 0}^{j - 1}g[i - 1][x]\]
可用前綴和優化為\(O(n^2)\)
那么
\[F(x,y) = \sum\limits_{i = 0}^{n}f[y][i]{n - i \choose x - y}\]
\[G(x,y) = \sum\limits_{i = 0}^{n}g[y][i]{n - i \choose x - y}\]
總復雜度\(O(Tn^2)\)
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<map> #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt) #define REP(i,n) for (int i = 1; i <= (n); i++) #define mp(a,b) make_pair<int,int>(a,b) #define cls(s) memset(s,0,sizeof(s)) #define cp pair<int,int> #define LL long long int using namespace std; const int maxn = 3005,maxm = 100005,INF = 1000000000,P = 998244353; inline int read(){int out = 0,flag = 1; char c = getchar();while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}return out * flag; } int n,m,K,fac[maxn],fv[maxn],inv[maxn]; int w1[maxn],w2[maxn]; int f[maxn][maxn],g[maxn][maxn]; int s[maxn]; void init(){fac[0] = fac[1] = inv[0] = inv[1] = fv[0] = fv[1] = 1;for (int i = 2; i <= 3000; i++){fac[i] = 1ll * fac[i - 1] * i % P;inv[i] = 1ll * (P - P / i) * inv[P % i] % P;fv[i] = 1ll * fv[i - 1] * inv[i] % P;} } inline int C(int n,int m){if (n < m) return 0;return 1ll * fac[n] * fv[m] % P * fv[n - m] % P; } inline int F(int x,int y){if (x > n || x < y) return 0;int re = 0;for (int i = 0; i <= n; i++)re = (re + 1ll * f[y][i] * C(n - i,x - y) % P) % P;return re; } inline int G(int x,int y){if (x > n || x < y) return 0;int re = 0;for (int i = 0; i <= n; i++)re = (re + 1ll * g[y][i] * C(n - i,x - y) % P) % P;return re; } inline bool cmp(const int& a,const int& b){return a > b; } void work(){sort(w1 + 1,w1 + 1 + n,cmp);sort(w2 + 1,w2 + 1 + n,cmp);for (int i = 0; i <= n; i++)for (int j = 0; j <= n; j++)f[i][j] = g[i][j] = 0;f[0][0] = 1;s[0] = 1;for (int i = 1; i <= n; i++) s[i] = s[i - 1];for (int i = 1; i <= n; i++){for (int j = i; j <= n; j++){f[i][j] = 1ll * w1[j] * s[j - 1] % P;}for (int j = 0; j < i; j++) s[j] = 0;for (int j = i; j <= n; j++) s[j] = (s[j - 1] + f[i][j]) % P;}s[0] = 0;for (int i = 1; i <= n; i++) s[i] = s[i - 1];for (int i = 1; i <= n; i++){for (int j = i; j <= n; j++){g[i][j] = (1ll * w2[j] * C(j - 1,i - 1) % P + s[j - 1]) % P;}for (int j = 0; j < i; j++) s[j] = 0;for (int j = i; j <= n; j++) s[j] = (s[j - 1] + g[i][j]) % P;}int ans = 0;for (int i = 0; i <= min(n,m); i++){int j = m - i; if (j < 0 || j > n) continue;if (i < K){ans = (ans + 1ll * F(i,i) * G(j,K - i) % P) % P;}else{ans = (ans + 1ll * F(i,K - 1) * G(j,1) % P) % P;}}printf("%d\n",ans); } int main(){init();int T = read();while (T--){n = read(); m = read(); K = read();REP(i,n) w1[i] = read();REP(i,n) w2[i] = read();work();}return 0; }轉載于:https://www.cnblogs.com/Mychael/p/9216259.html
總結
以上是生活随笔為你收集整理的loj2538 「PKUWC2018」Slay the Spire 【dp】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SQLSERVER 2014 SP1 的
- 下一篇: xgboost调参指南