题解 P5299 【[PKUWC2018]Slay the Spire】
TheLostWeak · · 题解
在博客查看
大致题意: 有
何为最优策略
这道题看似毫无头绪,因此,我们先要好好推一推性质。
假设现在我们已经选好了
首先,如果我们已经确定要用
因此我们把
同时,同样依据贪心,我们可以知道答案就是强化牌的乘积乘上攻击牌之和。
然后我们考虑,在什么情况下,把第
原先答案是:
变化后的答案是:
则两式相减,即为答案的变化量,也就是:
当变化后答案不变劣,说明变化量
我们把式子中的
由于题目中说明,强化牌权值大于
而在
所以我们可以发现,在
也就是说,在保有至少一张攻击牌的前提下,肯定是尽量选择强化牌会更优。
这么一来,这道题一下就可做得多了。
预处理
在正式开始解题之前,我们还需要进行预处理,定义几个变量。
设
同时,定义
则不难发现,有转移方程:
注意,
至于这些东西究竟有什么用,待会儿你就会知道了。
组合数学
接下来,就是分类讨论+推式子啦。
第一类:当
此时必然是选上所有的强化牌,然后选上权值最大的一些攻击牌。
不难发现,其实等于
对于这一种情况,我们枚举
在强化牌中选择
而强化牌中选择
而若要最终选出的
- 不存在强化牌。
- 所有攻击牌都必须在第
j 张之后,否则选这张攻击牌肯定比选第j 张优。
因此方案数就是
总结一下,就是枚举
第二类:当
此时必然是选上权值最大的
对于这一种情况,我们枚举
在前
选择第
而若要最终选出的
- 所有强化牌都必须在第
i 张之后。 - 所有攻击牌都必须在第
j 张之后。
因此方案数就是
总结一下,就是枚举
具体实现可见代码。
代码
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 6000
#define X 998244353
using namespace std;
int n,m,k,a[N+5],b[N+5],C[N+5][N+5],f[N+5][N+5][2],g[N+5][N+5][2];
I bool cmp(CI x,CI y) {return x>y;}
int main()
{
RI i,j;for(C[0][0]=i=1;i<=N;++i) for(C[i][0]=j=1;j<=i;++j) C[i][j]=(C[i-1][j-1]+C[i-1][j])%X;//预处理组合数
RI Tt,ans;scanf("%d",&Tt);W(Tt--)
{
for(scanf("%d%d%d",&n,&m,&k),ans=0,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,cmp),sort(b+1,b+n+1,cmp);//从大到小排序
for(f[0][0][0]=f[0][0][1]=i=1;i<=n;++i) for(f[i][0][1]=j=1;j<=i;++j)//预处理f
f[i][j][0]=1LL*a[i]*f[i-1][j-1][1]%X,f[i][j][1]=(f[i][j][0]+f[i-1][j][1])%X;
for(i=1;i<=n;++i) for(j=1;j<=i;++j)//预处理g
g[i][j][0]=(1LL*b[i]*C[i-1][j-1]+g[i-1][j-1][1])%X,g[i][j][1]=(g[i][j][0]+g[i-1][j][1])%X;
for(i=0;i<k-1;++i) for(j=1;j<=n;++j) ans=(1LL*f[n][i][1]*g[j][k-i][0]%X*C[n-j][m-k]+ans)%X;//当强化牌数量小于k-1时
for(i=0;i<=n;++i) for(j=1;j<=n;++j) ans=(1LL*f[i][k-1][0]*b[j]%X*C[2*n-i-j][m-k]+ans)%X;//当强化拍数量大于等于k-1时
printf("%d\n",ans);//输出答案
}return 0;
}