Problem
Solution
一道假的期望DP,其实就是考求和。。
显然出牌顺序必然是先出强化牌,再出攻击牌。那么要怎么组织出多少牌呢。。如果是出k张牌,那么必然是出k-1张强化牌,再打出一张最大的攻击牌。因为至少强化一倍,即如果替换掉一张强化牌而搞成攻击牌,原本受到的伤害为 A∗mx A ∗ m x ,更改后变为 Ak∗(mx+mx2) A k ∗ ( m x + m x 2 ) 。
这个最优选择的解决有点麻烦,我们想想怎么转化。显然我们肯定优先出数值更大的牌,那么不妨先排序,这样在dp的时候就可以愉快地把大小表示为序号。
设f[i][j]表示选的前i张强化牌最后一张选j的倍数 总和
f[i][j]=wj∑j−1r=i−1f[i−1][r] f [ i ] [ j ] = w j ∑ r = i − 1 j − 1 f [ i − 1 ] [ r ]
设g[i][j]表示选的前i张攻击牌最后一张选j的总和 总和
g[i][j]=Ci−1j−1wj+∑j−1r=i−1g[i−1][r] g [ i ] [ j ] = C j − 1 i − 1 w j + ∑ r = i − 1 j − 1 g [ i − 1 ] [ r ]
把后面的东西用前缀和来优化 O(n2) O ( n 2 )
F[i][j]/G[i][j]分别表示选i张相应的牌打出j张。可以这样考虑,枚举最后一张牌的出现位置,那么其他所有不出的牌必定在枚举的r之后(因为没那么优),用组合数解决之。
F[i][j]=∑nr=jCi−jn−rf[j][r] F [ i ] [ j ] = ∑ r = j n C n − r i − j f [ j ] [ r ]
G[i][j]=∑nr=jCi−jn−rg[j][r] G [ i ] [ j ] = ∑ r = j n C n − r i − j g [ j ] [ r ]
当然你并不需要把所有的F和G求出来,这样的复杂度高达 O(n3) O ( n 3 ) ,实质上只有一部分会被用到,在线处理一下。最后的ans就是枚举一下抽到多少张强化牌,然后稍微分类讨论一下即可。
每组数据时间复杂度 O(n2) O ( n 2 )
Code
#include <algorithm>
#include <cstring>
#include <cstdio>
#define rg register
using namespace std;
typedef long long ll;
const int maxn=3010,mod=998244353;
template <typename Tp> inline int getmin(Tp &x,Tp y){return y<x?x=y,1:0;}
template <typename Tp> inline int getmax(Tp &x,Tp y){return y>x?x=y,1:0;}
template <typename Tp> inline void read(Tp &x)
{
x=0;int f=0;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') f=1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
if(f) x=-x;
}
int z,n,m,k,ans,a[maxn],b[maxn],c[maxn][maxn];
int f[maxn][maxn],g[maxn][maxn],sf[maxn],sg[maxn];
inline int cmp(int x,int y){return x>y;}
inline int pls(int x,int y){return x+y>=mod?x+y-mod:x+y;}
void input()
{
read(n);read(m);read(k);ans=0;
for(rg int i=1;i<=n;i++) read(a[i]);
for(rg int i=1;i<=n;i++) read(b[i]);
sort(a+1,a+n+1,cmp);sort(b+1,b+n+1,cmp);
memset(sf,0,sizeof(sf));
memset(sg,0,sizeof(sg));
}
int F(int x,int y)
{
int res=0;
for(int i=y;i<=n;i++) res=pls(res,(ll)c[n-i][x-y]*f[y][i]%mod);
return res;
}
int G(int x,int y)
{
int res=0;
for(int i=y;i<=n;i++) res=pls(res,(ll)c[n-i][x-y]*g[y][i]%mod);
return res;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
read(z);
for(int i=0;i<=3000;i++)
{
c[i][0]=1;
for(rg int j=1;j<=i;j++) c[i][j]=pls(c[i-1][j-1],c[i-1][j]);
}
while(z--)
{
input();
f[0][0]=1;
for(rg int i=1;i<=n;i++) f[1][i]=a[i],g[1][i]=b[i];
for(rg int i=2;i<=n;i++)
for(rg int j=i;j<=n;j++)
{
sf[i-1]=pls(sf[i-1],f[i-1][j-1]);
f[i][j]=(ll)a[j]*sf[i-1]%mod;
sg[i-1]=pls(sg[i-1],g[i-1][j-1]);
g[i][j]=pls((ll)c[j-1][i-1]*b[j]%mod,sg[i-1]);
}
for(rg int i=0;i<=m&&i<=n;i++)
{
if(m-i>n) continue;
if(i<k) ans=pls(ans,(ll)F(i,i)*G(m-i,k-i)%mod);
else ans=pls(ans,(ll)F(i,k-1)*G(m-i,1)%mod);
}
printf("%d\n",ans);
}
return 0;
}