loj2538 「PKUWC 2018」Slay the Spire

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;
}

猜你喜欢

转载自www.cnblogs.com/poorpool/p/9065598.html