把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P5299 [PKUWC2018]Slay the Spire

题面传送门
看到这个平方的范围感觉像个dp。
首先考虑我们有\(m\)张牌应该怎么打,首先肯定是先打出所有强化再打所有攻击,那么伤害就是强化的乘积乘攻击的和。
考虑我们如果选择\(k'\)张强化,\(k-k'\)张攻击,那么一定是选择最大的强化和攻击。
考虑把一张攻击换成强化的过程,因为强化至少\(\times 2\),所以攻击要大于剩下攻击总和才能更劣,但是因为我们丢掉的是已选择中最小的攻击,所以除非只剩一张牌,否则这张牌都不会大于剩下的总和。因此我们的策略是:尽可能多选强化牌,直到没有强化牌选了或者攻击牌只有一张的时候停止。
现在问题变得可做起来,我们设\(f_{i,j}\)为强化选到了第\(i\)张,选了\(j\)张的,前\(\min(j-1,i)\)大的数乘积和,\(g_{i,j}\)为攻击选到第\(i\)张,选了\(j\)张的和。这两个都可以\(O(n^2)\)计算。
现在我们有两种情况:
第一种,强化选满了\(k-1\)张,此时攻击只会选一张,枚举选择了第\(i\)张攻击,并枚举攻击总共选了\(j\)张,对答案的贡献为\(B_i\times f_{n,m-j-1}\times C_{n-i}^{j-1}\)
第二种,强化没有选满\(k\)张,枚举选了\(j\)张强化,并枚举\(k-j\)张攻击的最小的一张在\(i\),对答案的贡献为\(f_{n,j}\times g_{i,k-j}\times C_{n-i}^{m-k}\)
综上,我们可以在\(O(n^2)\)时间内解决问题。
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define ll long long
#define db double
#define lb long db
#define N (3000+5)
#define M ((1<<20)+5)
#define Ks (12+5)
#define mod 998244353
#define Mod (mod-1)
#define eps (1e-9)
#define ull unsigned ll
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
#define R(n) (rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;
int n,m,k,x,y,z,T,A[N],B[N];ll Ans,dp[N][N],G[N],frc[N<<1],Inv[N<<1];
I ll mpow(ll x,int y=mod-2){ll Ans=1;while(y) y&1&&(Ans=Ans*x%mod),y>>=1,x=x*x%mod;return Ans;}
I ll C(int x,int y){if(y>x) return 0;return frc[x]*Inv[y]%mod*Inv[x-y]%mod;}
I void Solve(){
	int i,j,h;Ans=0;scanf("%d%d%d",&n,&m,&k);for(frc[0]=Inv[0]=i=1;i<=n*2;i++) frc[i]=frc[i-1]*i%mod,Inv[i]=mpow(frc[i]);for(i=1;i<=n;i++) scanf("%d",&A[i]);for(i=1;i<=n;i++) scanf("%d",&B[i]);
	sort(A+1,A+n+1);sort(B+1,B+n+1);reverse(A+1,A+n+1);reverse(B+1,B+n+1);Me(G,0);Me(dp[0],0);dp[0][0]=1;for(i=1;i<=n;i++){Me(dp[i],0);
		for(j=0;j<=min(i,m);j++) dp[i][j]=dp[i-1][j],j&&(dp[i][j]=(dp[i-1][j-1]*(j<k?A[i]:1)+dp[i][j])%mod);
	}
	for(i=0;i<=min(m,n);i++) G[i]=dp[n][i];
	for(i=1;i<=n;i++) for(j=k-1;j<m;j++) Ans+=B[i]*G[j]%mod*C(n-i,m-j-1)%mod/*,cerr<<i<<' '<<j<<' '<<Ans<<'\n';*/;
	Me(dp[0],0);
	for(i=1;i<=n;i++){Me(dp[i],0);
		for(j=0;j<=i;j++) dp[i][j]=dp[i-1][j],j&&(dp[i][j]=(dp[i][j]+dp[i-1][j-1]+B[i]*C(i-1,j-1))%mod);
	}
	for(i=0;i<k-1;i++){
		for(j=1;j<=n;j++) Ans+=(dp[j][k-i]-dp[j-1][k-i]+mod)*G[i]%mod*C(n-j,m-k)%mod;
	}printf("%lld\n",Ans%mod);
}
int main(){
	freopen("1.in","r",stdin);
	scanf("%d",&T);while(T--) Solve(); 
}
posted @ 2022-05-23 22:31  275307894a  阅读(17)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end