pkusc 快到了……做点题涨涨 rp。
ref我好菜啊QAQ。
显然的是,能打强化就打强化。记 \(m\) 张卡中分给强化卡的数量为 \(i\)。
那么 \(i < k\) 时,就打出 \(i\) 张强化卡,\(k-i\) 张攻击卡。
\(i \geq k-1\) 时,就打出 \(k-1\) 张强化卡,\(1\) 张攻击卡。
记 \(F(i,j)\) 为分给强化卡的数量为 \(i\),打出 \(j\) 张,所有方案翻的倍率的和。\(G(i,j)\) 为分给攻击卡的数量为 \(i\),打出 \(j\) 张,所有方案的攻击力之和的和。
两者分别对应 \(F(i,i) \times G(m-i,k-i)\) 和 \(F(i,k-1) \times G(m-i,1)\)。
关于 \(F\),可以 sort 以后定义一个 \(f\),\(f(i,j)\) 表示选了 \(i\) 张且最靠前的是第 \(j\) 个,这样推一推就好了。复杂度 \(O(n^2)\)。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
const int mod=998244353;
int T, n, m, k, a[1505], b[1505], c[3005][3005], f[1505][1505];
int g[1505][1505], sum[1505];
int F(int x, int y){
if(x<y) return 0;
if(!y) return c[n][x];
int re=0;
for(int j=x-y+1; j<=n-y+1; j++)
re = (re + (ll)f[y][j]*c[j-1][x-y]%mod) % mod;
return re;
}
int G(int x, int y){
if(x<y) return 0;
int re=0;
for(int j=x-y+1; j<=n-y+1; j++)
re = (re + (ll)g[y][j]*c[j-1][x-y]%mod) % mod;
return re;
}
int main(){
cin>>T;
for(int i=0; i<=3000; 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;
}
while(T--){
memset(f, 0, sizeof(f));
memset(g, 0, sizeof(g));
scanf("%d %d %d", &n, &m, &k);
for(int i=1; i<=n; i++) scanf("%d", &a[i]);
for(int i=1; i<=n; i++) scanf("%d", &b[i]);
sort(a+1, a+1+n);
sort(b+1, b+1+n);
for(int i=1; i<=n; i++){
f[1][i] = a[i];
sum[i] = (sum[i-1] + a[i]) % mod;
}
for(int i=2; i<=n; i++){
for(int j=1; j<=n-i+1; j++)
f[i][j] = (ll)a[j] * (sum[n]-sum[j]+mod) % mod;
for(int j=1; j<=n; j++)
sum[j] = (sum[j-1] + f[i][j]) % mod;
}
for(int i=1; i<=n; i++){
g[1][i] = b[i];
sum[i] = (sum[i-1] + b[i]) % mod;
}
for(int i=2; i<=n; i++){
for(int j=1; j<=n-i+1; j++)
g[i][j] = ((ll)b[j]*c[n-j][i-1]%mod+(sum[n]-sum[j]+mod)%mod) % mod;
for(int j=1; j<=n; j++)
sum[j] = (sum[j-1] + g[i][j]) % mod;
}
int ans=0;
for(int i=0; i<m; i++)
if(i<k) ans = (ans + (ll)F(i,i)*G(m-i,k-i)%mod) % mod;
else ans = (ans + (ll)F(i,k-1)*G(m-i,1)%mod) % mod;
printf("%d\n", ans);
}
return 0;
}