loj #2538. 「PKUWC2018」Slay the Spire

$ \color{#0066ff}{ 题目描述 }$

九条可怜在玩一个很好玩的策略游戏:Slay the Spire,一开始九条可怜的卡组里有 \(2n\) 张牌,每张牌上都写着一个数字\(w_i\),一共有两种类型的牌,每种类型各 \(n\) 张:

  1. 攻击牌:打出后对对方造成等于牌上的数字的伤害。
  2. 强化牌:打出后,假设该强化牌上的数字为\(x\),则其他剩下的攻击牌的数字都会乘上 \(x\)保证强化牌上的数字都大于 1

现在九条可怜会等概率随机从卡组中抽出 \(m\) 张牌,由于费用限制,九条可怜最多打出 \(k\) 张牌,假设九条可怜永远都会采取能造成最多伤害的策略,求她期望造成多少伤害。

假设答案为 \(\text{ans}\),你只需要输出

\(\left (\text{ans}\times \frac{(2n)!}{m!(2n-m)!}\right) ~\bmod 998244353\)

即可

其中 \(x!\) 表示 \(\prod_{i=1}^{x}i\),特别地,\(0!=1\)

\(\color{#0066ff}{输入格式}\)

第一行一个正整数 \(T\) 表示数据组数

接下来对于每组数据:

第一行三个正整数 \(n,m,k\)

第二行 \(n\) 个正整数 \(w_i\),表示每张强化牌上的数值。

第三行 \(n\) 个正整数 \(w_i\),表示每张攻击牌上的数值。

\(\color{#0066ff}{输出格式}\)

输出 \(T\) 行,每行一个非负整数表示每组数据的答案。

\(\color{#0066ff}{输入样例}\)

2
2 3 2
2 3
1 2
10 16 14
2 3 4 5 6 7 8 9 10 11
1 2 3 4 5 6 7 8 9 10

\(\color{#0066ff}{输出样例}\)

19
253973805

\(\color{#0066ff}{数据范围与提示}\)

对于所有数据,有 \(1\leq k\leq m\leq 2n\leq 3\times 10^3\),且\(1\leq w_i\leq 10^8\)

保证强化牌上的数字都大于 1

以下 \((\sum 2n)\) 表示对于输入中所有数据的\(2n\)的和。

对于 \(10\%\) 的数据,有 \(1\leq \sum 2n\leq 10\)

对于 \(20\%\) 的数据,有 \(1\leq \sum 2n\leq 100\)

对于 \(30\%\) 的数据,有 \(1\leq \sum 2n\leq 500\)

另有 \(20\%\) 的数据,满足所有攻击牌的数值相同。

另有 \(20\%\) 的数据,满足 \(m=k\)

对于 \(100\%\) 的数据,有 \(1\leq \sum 2n\leq 30000\)

\(\color{#0066ff}{题解}\)

假如说我们已经有了m张牌,现在考虑怎么打出k张牌会最优呢
首先,一定是先打强化牌再打攻击牌最优,不解释
那么到底选多少攻击牌和强化牌呢
首先,我们先把m张牌分两类从大到小排序,那么肯定是选两类牌的一个前缀
比如,强化3 2, 攻击a b,\(k=3\)
那么显然\(2*3*a=3a+3a>3a+3b\)
因此,我们要尽可能多的选强化牌,剩下的选攻击牌
我们设状态\(f[i][j][0/1]\)表示强化牌中,前i张选j张,第i张选不选(这是为了统计方案不重不漏)的贡献
举个锤子,比如强化牌5 4 3 2,那么\(f[4][3][1]\)就是\(2 * 3 * 5+2 * 4 * 5+2 * 3 * 4\),就是所有合法贡献的和
同理\(g[i][j][0/1]\)是针对ATK的DP
转移很容易,\(O(n^2)\)
f[0][0][0] = 1; 
for(int i = 1; i <= n; i++) {
    for(int j = 0; j <= i; j++) {
        if(j >= 1) {
            f[i][j][1] = ((f[i - 1][j - 1][1] + f[i - 1][j - 1][0]) % mod * STG[i] % mod);
            g[i][j][1] = ((g[i - 1][j - 1][1] + g[i - 1][j - 1][0]) % mod + ATK[i] * C(i - 1, j - 1) % mod) % mod;
        }
        f[i][j][0] = (f[i - 1][j][0] + f[i - 1][j][1]);
        g[i][j][0] = (g[i - 1][j][0] + g[i - 1][j][1]);
    }
}
之后我们开始统计方案
为了不重不漏,我们分别在两个序列枚举端点i和j
首先考虑已有的m张牌中,强化牌\(\ge k-1\)
那么我们肯定是选前\(k-1\)张大的强化牌和1张攻击牌, 剩下的\(m-k\)放在其它位置

\(f[i][k-1][1]*g[j][1][1]*C_{2n -i-j}^{m-k}\)

如果没有那么多,只只有\(w,w<k-1\)张,我们肯定都选,然后剩下的\(k-w\)张是攻击牌,注意,这时候剩下的\(m-k\)张牌必须只能是攻击牌, 因为强化牌不够!

\(f[i][w][1]*g[j][k-w][1]*C_{n-j}^{m-k}\)

注意当不选强化牌的时候要特判一下,即\(k=1\)的时候,还有\(k\ne 1\)时不选强化牌的情况,直接统计方案的话因为f是0,所以最后就是0,显然不对了,单独算一下就行
#include<bits/stdc++.h>
#define LL long long
LL in() {
    char ch; LL x = 0, f = 1;
    while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    return x * f;
}
const int mod = 998244353;
const int maxn = 3030;
LL f[maxn][maxn][2], g[maxn][maxn][2];
LL ATK[maxn], STG[maxn], fac[maxn << 1], inv[maxn << 1];
int n, m, k;
LL ksm(LL x, LL y) {
    LL re = 1LL;
    while(y) {
        if(y & 1) re = re * x % mod;
        x = x * x % mod;
        y >>= 1;
    }
    return re;
}
LL C(int x, int y) { 
    if(x < y) return 0;
    return fac[x] * inv[y] % mod * inv[x - y] % mod; 
}
void predoit() {
    std::sort(STG + 1, STG + n + 1, std::greater<LL>());
    std::sort(ATK + 1, ATK + n + 1, std::greater<LL>());
    f[0][0][0] = 1; 
    for(int i = 1; i <= n; i++) {
        for(int j = 0; j <= i; j++) {
            if(j >= 1) {
                f[i][j][1] = ((f[i - 1][j - 1][1] + f[i - 1][j - 1][0]) % mod * STG[i] % mod);
                g[i][j][1] = ((g[i - 1][j - 1][1] + g[i - 1][j - 1][0]) % mod + ATK[i] * C(i - 1, j - 1) % mod) % mod;
            }
            f[i][j][0] = (f[i - 1][j][0] + f[i - 1][j][1]);
            g[i][j][0] = (g[i - 1][j][0] + g[i - 1][j][1]);
        }
    }
}
void fuck() {
    LL ans = 0;
    for(int i = k - 1; i <= n; i++) 
        for(int j = 1; j <= n; j++)
            (ans += f[i][k - 1][1] * g[j][1][1] % mod * C((n << 1) - i - j, m - k) % mod) %= mod;
    for(int w = 1; w <= k - 2; w++) {
        LL tot = 0;
        for(int i = 1; i <= n; i++) (tot += f[i][w][1]) %= mod;
        for(int i = 1; i <= n; i++) (ans += tot * g[i][k - w][1] % mod * C(n - i, m - k) % mod) %= mod;
    }
    for(int i = 1; i <= n; i++) (ans += g[i][k][1] * C(n - i, m - k) % mod) %= mod;
    printf("%lld\n", ans);
}
void work() {
    LL ans = 0;
    for(int i = 1; i <= n; i++) (ans += ATK[i] * C((n << 1) - i, m - k) % mod) %= mod;
    printf("%lld\n", ans);
}

int main() {
    fac[0] = 1;
    for(LL i = 1; i <= 6000; i++) fac[i] = i * fac[i - 1] % mod;
    inv[6000] = ksm(fac[6000], mod - 2);
    for(LL i = 5999; i >= 0; i--) inv[i] = (i + 1) * inv[i + 1] % mod;
    for(int T = in(); T --> 0;) {
        n = in(), m = in(), k = in();
        for(int i = 1; i <= n; i++) STG[i] = in();
        for(int i = 1; i <= n; i++) ATK[i] = in();
        predoit();
        if(k == 1) work();
        else fuck();
    }
    return 0;
}

转载于:https://www.cnblogs.com/olinr/p/10518444.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园的建设目标是通过数据整合、全面共享,实现校园内教学、科研、管理、服务流程的数字化、信息化、智能化和多媒体化,以提高资源利用率和管理效率,确保校园安全。 智慧校园的建设思路包括构建统一支撑平台、建立完善管理体系、大数据辅助决策和建设校园智慧环境。通过云架构的数据中心与智慧的学习、办公环境,实现日常教学活动、资源建设情况、学业水平情况的全面统计和分析,为决策提供辅助。此外,智慧校园还涵盖了多媒体教学、智慧录播、电子图书馆、VR教室等多种教学模式,以及校园网络、智慧班牌、校园广播等教务管理功能,旨在提升教学品质和管理水平。 智慧校园的详细方案设计进一步细化了教学、教务、安防和运维等多个方面的应用。例如,在智慧教学领域,通过多媒体教学、智慧录播、电子图书馆等技术,实现教学资源的共享和教学模式的创新。在智慧教务方面,校园网络、考场监控、智慧班牌等系统为校园管理提供了便捷和高效。智慧安防系统包括视频监控、一键报警、阳光厨房等,确保校园安全。智慧运维则通过综合管理平台、设备管理、能效管理和资产管理,实现校园设施的智能化管理。 智慧校园的优势和价值体现在个性化互动的智慧教学、协同高效的校园管理、无处不在的校园学习、全面感知的校园环境和轻松便捷的校园生活等方面。通过智慧校园的建设,可以促进教育资源的均衡化,提高教育质量和管理效率,同时保障校园安全和提升师生的学习体验。 总之,智慧校园解决方案通过整合现代信息技术,如云计算、大数据、物联网和人工智能,为教育行业带来了革命性的变革。它不仅提高了教育的质量和效率,还为师生创造了一个更加安全、便捷和富有智慧的学习与生活环境。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值