$ \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. JavaScript之BON

    1.windows对象 全局作用域: 2.窗口关系及框架 如果页面包含框架,则每个框架都有自己的window对象,并且保存在iframes集合中,在iframe集合中,可以通过数值索引(从0开始,从左 ...

  2. 前端自动化之nvm安装

    nvm ——node环境版本控制工具. 1.解压安装包 2.打开setting文件,修改文件内容 root: D:\node\nvm path: D:\node\nodejs arch: proxy: ...

  3. Minimum Sum of Array(map)

    You are given an array a consisting of n integers a1, ..., an. In one operation, you can choose 2 el ...

  4. 移植RT2870无线网卡驱动到s3c2416

    公司项目要用到usb无线网卡,芯片是ralink的RT2870.以下是将其驱动移植到s3c2416的步骤. 1.下载驱动源码,雷凌官网的下载地址是: http://www.ralinktech.com ...

  5. MySQL与SQLServer的update left join语法区别

    需求: 表A 字段 A_ID, A_NAME, B_ID 表B 字段 B_ID, B_NAME 需求把A的所有A_NAME更新为相应的B的 B_NAME. mysql做法: UPDATE A LEFT ...

  6. js的两种查询方式 LHS and RHS

    为了进一步理解,我们需要多介绍一点编译器的术语.编译器在编译过程的第二步中生成了代码,引擎执行它时,会通过查找变量 a 来判断它是否已声明过.查找的过程由作用域进行协助,但是引擎执行怎样的查找,会影响 ...

  7. c++ 多态问题(在虚函数里调用虚函数)

    最近在看cocos2d-x的源码,非常感激cocos2d作者的开源精神.在看代码的过程中感觉两个方向让我受益,1.把之前从书中看到的c++知识,明白了怎么运用.2.学习作者驾驭代码的巧妙方法. 看co ...

  8. C++ 输出精度和输出小数点位数

    有时候需要调节小数点的精度或者位数 #include<iostream> #include<iomanip> using namespace std; //设置数据精度 set ...

  9. linux环境配置与使用合集

    配置linux和samba共享 1. 安装linux操作系统 2. 通过windows操作系统ping linux看看是否可以ping通 3. 相关软件安装 a. 安装samba sudo apt-g ...

  10. 【Leetcode009】Palindrome Number

    问题链接:https://leetcode.com/problems/palindrome-number/#/description Question:Determine whether an int ...