P5299 [PKUWC2018]Slay the Spire

在最少出一张攻击牌,尽量多的打强化牌,因为它至少让牌翻倍,排序选出最大攻击牌,强化牌不够,再打出较大攻击牌

\(f_{i,j}\)为考虑了排序后的前 \(i\) 张强化牌且第 \(i\) 张必选,选了 \(j\) 张牌的效果,\(g_{i,j}\)为考虑了排序后的前 \(i\) 张攻击牌且第 \(i\) 张必选,选了 \(j\) 张牌的效果,得:

\[f[i][j]=v_i\sum_{k=j-1}^{i-1}f[k][j-1]\\ g[i][j]={i-1\choose j-1}v_i+\sum_{k=j-1}^{i-1}g[k][j-1] \]

考虑\(f,g\)\(F,G\)贡献

\[F[i][j]=\sum_{k=j}^n{n-k\choose i-j}f[k][j]\\ G[i][j]=\sum_{k=j}^n{n-k\choose i-j}g[k][j] \]

#include<cstdio>
#include<algorithm>
#define mod 998244353
using namespace std;
const int maxn = 3001;
inline int read() {
	char c=std::getchar();int x=0;while(c<'0'||x>'9') c=std::getchar();
	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=std::getchar();return x;
}
int c[maxn][maxn],dp[maxn][maxn],f[maxn][maxn];
int g[maxn][maxn],h[maxn][maxn];
int n,m,k;
int a[maxn],b[maxn];
bool cmp(int a,int b){return a > b;}
inline int C(int n,int m){return m > n ? 0 : c[n][m];}
int main(){
	int T,M=2000;T = read();
	for(int i = 0;i <= M;i++) c[i][0] = c[i][i] = 1;
		for(int i = 1;i <= M;i++)
			for(int j = 1;j < i;j++)
				c[i][j] = (c[i-1][j] + c[i-1][j-1]) % mod;
	while(T--){
		n = read();m = read();k = read();
		for(int i = 1;i <= n;i++) a[i] = read();
		for(int i = 1;i <= n;i++) b[i] = read();
		std::sort(a+1,a+n+1,cmp); std::sort(b+1,b+n+1,cmp);
		dp[0][0] = 1;
		for(int i=1;i<=n;i++)
			for(int j=0;j<=i;j++) {
				dp[i][j]=dp[i-1][j];
				if(j) dp[i][j]=(dp[i][j]+1ll*dp[i-1][j-1]*a[i]%mod)%mod;
			}
		f[0][0]=1;
		for(int i=1;i<=n;i++) 
			for(int j=1;j<=i;j++) 
				f[i][j]=1ll*dp[i-1][j-1]*a[i]%mod;
		h[0][0]=0;
		for(int i=1;i<=n;i++)
			for(int j=0;j<=i;j++) {
				h[i][j]=h[i-1][j];
				if(j) h[i][j]=(h[i][j]+1ll*C(i-1,j-1)*b[i]%mod+h[i-1][j-1])%mod;
			}
		for(int i=1;i<=n;i++)
			for(int j=1;j<=i;j++)
				g[i][j]=(1ll*C(i-1,j-1)*b[i]%mod+h[i-1][j-1])%mod;
		int ans=0;
		for(int i=0;i<m;i++) {
			int now=0;
			for(int j=0;j<=n;j++) {
				if(i<=k-1) now=(now+f[j][i])%mod;
					else now=(now+1ll*f[j][k-1]*C(n-j,i-k+1)%mod)%mod;
			}
			int tot=0,res=0;
			if(i<=k-1) res=k-i;else res=1;
			for(int j=0;j<=n;j++) 
				tot=(tot+1ll*g[j][res]*C(n-j,m-i-res)%mod)%mod;
			ans=(ans+1ll*now*tot%mod)%mod;
		}
		printf("%d\n",ans);
	}
} 
posted @ 2020-08-14 16:00  INFP  阅读(111)  评论(0编辑  收藏  举报