解题思路:
做这道题时一定要静下心来思考,不能慌……
假设摸到
i
i
张强化牌,张攻击牌。
首先发现强化牌数值都大于1,所以有一个显然的结论,强化牌能用就用,即:
i<k
i
<
k
,用
i
i
张强化牌, 张最大的攻击牌;
i≥k
i
≥
k
,用
k−1
k
−
1
张强化牌和最大的攻击牌;
那么先把牌从大到小排,
fi,j
f
i
,
j
表示前
i
i
张强化牌摸了 张能翻的倍数和,
gi,j
g
i
,
j
类似。
统计答案时枚举用的张数和断点(因为要用较大的牌,肯定在前面),后面摸了但没用的乘以组合数即可。(其实这是细节最多,最需要想的一步)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int getint()
{
ll i=0,f=1;char c;
for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar());
if(c=='-')c=getchar(),f=-1;
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
const int N=3005,mod=998244353;
int n,m,k;
ll ans,a[N],b[N],c[N][N],f[N][N][2],g[N][N][2];
inline bool cmp(const int &a,const int &b){return a>b;}
void solve()
{
n=getint(),m=getint(),k=getint(),ans=0;
for(int i=1;i<=n;i++)a[i]=getint();
for(int i=1;i<=n;i++)b[i]=getint();
sort(a+1,a+n+1,cmp),sort(b+1,b+n+1,cmp);
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)
f[i][j][0]=g[i][j][0]=f[i][j][1]=g[i][j][1]=0;
f[0][0][1]=1;
for(int i=1;i<=n;i++)
for(int j=0;j<=n;j++)
{
f[i][j][0]=(f[i-1][j][0]+f[i-1][j][1])%mod;
if(j)f[i][j][1]=(f[i-1][j-1][0]+f[i-1][j-1][1])*a[i]%mod;
g[i][j][0]=(g[i-1][j][0]+g[i-1][j][1])%mod;
if(j)g[i][j][1]=(g[i-1][j-1][0]+g[i-1][j-1][1]+c[i-1][j-1]*b[i])%mod;
}
for(int i=0;i<m;i++)
{
int j=m-i;
if(i<k)
{
for(int l=k-i;l<=n-(m-k);l++)
ans=(ans+(f[n][i][0]+f[n][i][1])*g[l][k-i][1]%mod*c[n-l][m-k])%mod;
}
else
{
ll tmp=0;
for(int l=1;l<=n;l++)tmp=(tmp+b[l]*c[n-l][m-i-1])%mod;
for(int l=k-1;l<=n-(i-k+1);l++)ans=(ans+f[l][k-1][1]*c[n-l][i-k+1]%mod*tmp)%mod;
}
}
cout<<ans<<'\n';
}
int main()
{
//freopen("lx.in","r",stdin);
for(int i=0;i<N;i++)
{
c[i][0]=1;
for(int j=1;j<=i;j++)
c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
}
for(int T=getint();T;T--)solve();
return 0;
}