「PKUWC2018」Slay the Spire
國際慣例不放題干
扯淡
其實題目翻譯過來是殺戮尖塔,某steam上的卡牌游戲,我也曾熱衷刷榜
題解
首先題目中要求的期望是假期望,結合題目中所給的階乘就可以看出這其實是從$2*n$張牌中選擇$m$張牌使用,并且所有情況都取最大值時的和
首先排序貪心最大
再說一個非常顯然的結論,有強化牌就用,強化牌上數大于2,所以打出強化牌一定收益>=比打出一張攻擊牌帶來(保證最后一定要出至少一張攻擊牌就行)
例如? 你有強化牌? 2 2 攻擊牌 4 4 限制出2張
那么你先打一張2再打一張4和 先打4 再打4 收益一樣 ?
那么如果強化牌比k張要小,那么要把所有強化牌都用了,最后打輸出.如果強化牌比k還要大,那么最后留一張攻擊牌打出來就行了
我們可以假設$F(i,j)$表示你有i張強化牌時打出j張時收益,$G(i,j)$表示你有i張攻擊牌時打出j張時收益
那么最后答案就是
$\sum\limits_{i=0}^{k-1} F(i,i)*G(m-i,k-i)+\sum\limits_{i=k}^{k=min(n,m)} F(i,k-1)*G(m-i,1)$
那么我們現在的任務就是快速求出來F和G
考慮直接求非常難求,我們這時一般要開幾個別的數組
首先開$f[i][j]$ $g[i][j]$表示當你抽到i張牌必打第i張一共打了j張時收益
那么可以推出來$f[i][j]=w_i\times \sum f[l][j-1]$和$g[i][j]=C_{i-1}^{j-1}w_i + \sum g[l][j-1]$ (這里的組合數表示一共有$C_{i-1}^{j-1}$種方式轉移過來,每種轉移都要加一個w)
然后得到$F(i,j)=\sum_{l=j}^{n} C_{n-l}^{i-j} f[l][j]$
解釋一下 F可以從l中使用j張(這j張都是大牌)再從剩余n-l中選擇i-j張不打共同構成F的i張打了j張
G同理得到$G(i,j)=\sum{l=j}^{n} C_{n-l}^{i-j} g[i][j]$
然后轉移就完了
本題稍卡常
代碼
#include<bits/stdc++.h> using namespace std; #define ll long long #define A 1510 #define py printf("f**k\n") #define mod 998244353 ll n,m,t,k,ans=0,f[1510][1510],g[1510][1510],C[3010][3010],sum1[A],sum2[A],wg[A],wq[A]; inline ll read() {ll x=0; char c=getchar();while(isdigit(c)){x=x*10+c-'0';c=getchar();}return x; } ll gcd(ll x,ll y){if(y==0) return x;return gcd(y,x%y); } inline ll F(ll i,ll j){ll r=0;for(ll l=j;l<=n;l++){r=(r+C[n-l][i-j]*f[l][j]%mod)%mod;//表示含義為首先從前l張選出j張再從n-l中選出l-j張 }return r; } inline bool cmp(const ll & a,const ll & b){return a>b; } inline ll G(ll i,ll j){ll r=0;for(ll l=j;l<=n;l++){r=(r+C[n-l][i-j]*g[l][j]%mod)%mod;//含義同上 }return r; } inline void re(){memset(sum1,0,sizeof(sum1));memset(sum2,0,sizeof(sum2)); } inline void init(){n=read(),m=read(),k=read();f[0][0]=1;for(ll i=1;i<=n;i++)wq[i]=read();sort(wq+1,wq+n+1,cmp);for(ll i=1;i<=n;i++)wg[i]=read();sort(wg+1,wg+n+1,cmp);for(ll i=1;i<=n;i++)f[i][1]=wq[i],g[i][1]=wg[i];for(ll i=1;i<=n;i++){for(ll j=2;j<=i;j++){sum1[j-1]=(sum1[j-1]+f[i-1][j-1])%mod;f[i][j]=wq[i]*sum1[j-1]%mod;sum2[j-1]=(sum2[j-1]+g[i-1][j-1])%mod;g[i][j]=(C[i-1][j-1]*wg[i]+(sum2[j-1]))%mod;}} /* for(ll i=1;i<=n;i++)for(ll j=1;j<=i;j++)printf("f[%lld][%lld]=%lld g[%lld][%lld]=%lld\n",i,j,f[i][j],i,j,g[i][j]); */} inline void work(){ll ans=0;for(ll i=min(n,m);i>=0;i--){if(i<k)ans=(ans+F(i,i)*G(m-i,k-i)%mod)%mod/*,printf("F=%lld G=%lld\n",F(i,i),G(m-i,k-i))*/;else ans=(ans+F(i,k-1)*G(m-i,1)%mod)%mod/*,printf("F=%lld G=%lld\n",F(i,k-1),G(m-i,1))*/; // printf("ans=%lld\n",ans); }printf("%lld\n",ans); } int main() {for(ll i=0;i<=3000;i++)C[i][0]=1;for(ll i=1;i<=3000;i++)for(ll j=1;j<=i;j++)C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;t=read();while(t--){re();init();work();} }?
轉載于:https://www.cnblogs.com/znsbc-13/p/11238425.html
總結
以上是生活随笔為你收集整理的「PKUWC2018」Slay the Spire的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux系统分为哪几类?
- 下一篇: 一个iOS表单框架-UFKit