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

loj #2538. 「PKUWC2018」Slay the Spire的更多相关文章

  1. 【LOJ】#2538. 「PKUWC2018」Slay the Spire

    题解 由于强化卡都是大于1的,我们分析一下就会发现,尽可能多的用强化卡,至少用一张攻击卡,一定是每组卡牌的最优选择 所以我们把攻击卡和强化卡从大到小排序 我们设\(g[i][j]\)表示前i张卡牌里选 ...

  2. LOJ2538. 「PKUWC2018」Slay the Spire【组合数学】

    LINK 思路 首先因为式子后面把方案数乘上了 所以其实只用输出所有方案的攻击力总和 然后很显然可以用强化牌就尽量用 因为每次强化至少把下面的牌翻一倍,肯定是更优的 然后就只有两种情况 强化牌数量少于 ...

  3. loj2538 「PKUWC2018」Slay the Spire 【dp】

    题目链接 loj2538 题解 比较明显的是,由于强化牌倍数大于\(1\),肯定是能用强化牌尽量用强化牌 如果强化牌大于等于\(k\),就留一个位给攻击牌 所以我们将两种牌分别排序,企图计算\(F(i ...

  4. 「PKUWC2018」Slay the Spire

    题目链接 题意分析 这个题其实不是期望 就是一共有\(C_{2n}^m\)种情况 每一种情况选择\(k\)张牌 然后求最大攻击值的总和 我们考虑 当前抽出了选出了\(i\)张强化牌 \(m-i\)张攻 ...

  5. Loj #2542. 「PKUWC2018」随机游走

    Loj #2542. 「PKUWC2018」随机游走 题目描述 给定一棵 \(n\) 个结点的树,你从点 \(x\) 出发,每次等概率随机选择一条与所在点相邻的边走过去. 有 \(Q\) 次询问,每次 ...

  6. loj#2537. 「PKUWC2018」Minimax

    题目链接 loj#2537. 「PKUWC2018」Minimax 题解 设\(f_{u,i}\)表示选取i的概率,l为u的左子节点,r为u的子节点 $f_{u,i} = f_{l,i}(p \sum ...

  7. LOJ #2541「PKUWC2018」猎人杀

    这样$ PKUWC$就只差一道斗地主了 假装补题补完了吧..... 这题还是挺巧妙的啊...... LOJ # 2541 题意 每个人有一个嘲讽值$a_i$,每次杀死一个人,杀死某人的概率为$ \fr ...

  8. LOJ #2542「PKUWC2018」随机游走

    $ Min$-$Max$容斥真好用 $ PKUWC$滚粗后这题一直在$ todolist$里 今天才补掉..还要更加努力啊.. LOJ #2542 题意:给一棵不超过$ 18$个节点的树,$ 5000 ...

  9. LOJ 2542 「PKUWC2018」随机游走 ——树上高斯消元(期望DP)+最值反演+fmt

    题目:https://loj.ac/problem/2542 可以最值反演.注意 min 不是独立地算从根走到每个点的最小值,在点集里取 min ,而是整体来看,“从根开始走到点集中的任意一个点就停下 ...

随机推荐

  1. JS播放声音 兼容所有浏览器

    JS播放声音 兼容所有浏览器 <!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" "http ...

  2. leetcode682

    class Solution { public: int calPoints(vector<string>& ops) { stack<int> ST; ; for ( ...

  3. 非常详细的ok6410的linux系统移植…

    目录 Linux 3.3.5系统移植 2 LED驱动移植 8 按键驱动移植 9 LCD驱动移植 11 DM9000网卡驱动移植 14 搭建NFS网络文件系统 25 移植触摸屏驱动 38 移植Qt4.8 ...

  4. 获取文件的后缀名。phpinfo

    1: function get_extension($file){ //strrchr 返回 .jpg substr :1 是从1开始. substr(strrchr($file,'.'),1) } ...

  5. java 从jsp页面传集合给controller

    <%@ page language="java" import="java.util.*" pageEncoding="utf-8"% ...

  6. ubuntu16.04 ARM平台移植xmlrpc-c1.39.12

    1. xmlrpc-c依赖与libcurl 参考另外一篇随笔:https://www.cnblogs.com/flyinggod/p/10148228.html 2. 下载源代码 http://xml ...

  7. javascript nonono

    javascript实现的点击元素实现当前轮换展现效果 javascript实现的点击元素实现当前轮换展现效果:本章节分享一段代码实例,它实现了点击元素实现当前展现效果,并且具有比较人性化的变换效果. ...

  8. Django框架 之 中间件

    Django框架 之 中间件 浏览目录 中间件介绍 自定义中间件 中间件的执行流程 中间件版登录验证 一.中间件介绍 官方的说法:中间件是一个用来处理Django的请求和响应的框架级别的钩子.它是一个 ...

  9. Part6-点亮指路灯_lesson1

    1. 2.GPIO 查阅芯片手册:GPIO 代码: 3.外设基地址初始化 打开arm核手册, 基地址为0x70000000,去搜芯片手册6410, 把这个基地址告诉处理器,通过协处理器的cp15, 转 ...

  10. Servlet请求转发 RequestDispatcher接口.RP

    在Servlet中,利用RequestDispatcher对象,可以将请求转发给另外一个Servlet或JSP页面,甚至是HTML页面,来处理对请求的响应. 一,RequestDispatcher接口 ...