loj #2538. 「PKUWC2018」Slay the Spire
$ \color{#0066ff}{ 题目描述 }$
九条可怜在玩一个很好玩的策略游戏:Slay the Spire,一开始九条可怜的卡组里有 \(2n\) 张牌,每张牌上都写着一个数字\(w_i\),一共有两种类型的牌,每种类型各 \(n\) 张:
- 攻击牌:打出后对对方造成等于牌上的数字的伤害。
- 强化牌:打出后,假设该强化牌上的数字为\(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的更多相关文章
- 【LOJ】#2538. 「PKUWC2018」Slay the Spire
题解 由于强化卡都是大于1的,我们分析一下就会发现,尽可能多的用强化卡,至少用一张攻击卡,一定是每组卡牌的最优选择 所以我们把攻击卡和强化卡从大到小排序 我们设\(g[i][j]\)表示前i张卡牌里选 ...
- LOJ2538. 「PKUWC2018」Slay the Spire【组合数学】
LINK 思路 首先因为式子后面把方案数乘上了 所以其实只用输出所有方案的攻击力总和 然后很显然可以用强化牌就尽量用 因为每次强化至少把下面的牌翻一倍,肯定是更优的 然后就只有两种情况 强化牌数量少于 ...
- loj2538 「PKUWC2018」Slay the Spire 【dp】
题目链接 loj2538 题解 比较明显的是,由于强化牌倍数大于\(1\),肯定是能用强化牌尽量用强化牌 如果强化牌大于等于\(k\),就留一个位给攻击牌 所以我们将两种牌分别排序,企图计算\(F(i ...
- 「PKUWC2018」Slay the Spire
题目链接 题意分析 这个题其实不是期望 就是一共有\(C_{2n}^m\)种情况 每一种情况选择\(k\)张牌 然后求最大攻击值的总和 我们考虑 当前抽出了选出了\(i\)张强化牌 \(m-i\)张攻 ...
- Loj #2542. 「PKUWC2018」随机游走
Loj #2542. 「PKUWC2018」随机游走 题目描述 给定一棵 \(n\) 个结点的树,你从点 \(x\) 出发,每次等概率随机选择一条与所在点相邻的边走过去. 有 \(Q\) 次询问,每次 ...
- loj#2537. 「PKUWC2018」Minimax
题目链接 loj#2537. 「PKUWC2018」Minimax 题解 设\(f_{u,i}\)表示选取i的概率,l为u的左子节点,r为u的子节点 $f_{u,i} = f_{l,i}(p \sum ...
- LOJ #2541「PKUWC2018」猎人杀
这样$ PKUWC$就只差一道斗地主了 假装补题补完了吧..... 这题还是挺巧妙的啊...... LOJ # 2541 题意 每个人有一个嘲讽值$a_i$,每次杀死一个人,杀死某人的概率为$ \fr ...
- LOJ #2542「PKUWC2018」随机游走
$ Min$-$Max$容斥真好用 $ PKUWC$滚粗后这题一直在$ todolist$里 今天才补掉..还要更加努力啊.. LOJ #2542 题意:给一棵不超过$ 18$个节点的树,$ 5000 ...
- LOJ 2542 「PKUWC2018」随机游走 ——树上高斯消元(期望DP)+最值反演+fmt
题目:https://loj.ac/problem/2542 可以最值反演.注意 min 不是独立地算从根走到每个点的最小值,在点集里取 min ,而是整体来看,“从根开始走到点集中的任意一个点就停下 ...
随机推荐
- MyEclipse jQuery智能 提示
jQuery智能 MyEclipse Spket IDE 1.6.23 http://www.spket.com/download.html Plugin 1.6.23 5.62 MB Minimum ...
- hibernate反向生成奇葩错误
错误场景 最近搞一个hibernate的项目,由于好久不用hibernate了,稍微有点生疏(自从用了ibatis–>mybatis后).这个项目用了hibernate,和ibatis.myba ...
- 2-3 JAVA内存模型
- day58-activiti 02-历史数据查询
Activity 笔记 第二天 今天内容安排: 1.历史数据查询 办过多少个任务, 这些历史数据有时候我们也需要去查询一下. 本身day02这个项目就没有导jar包,有点类似于maven,在你的项目 ...
- linux tcpdump补充
If they are going across the loopback interface, you may have to tell tcpdump to read that interface ...
- 非root配置linux下vim
在机子目录下建立 .vim文件夹 例如 /home/xxx/.vim 在~文件夹下建立.vimrc文件 这是你自己配置文件 vim虽然启用了格式化高亮.行号显示,以及括号匹配.自动缩进等编辑功能,对于 ...
- web Servise(服务)
服务层:对项目的业务层(业务层调用数据层)的一个包装成对外的服务,是的UI展示可以从单一的WEB扩展为移动端可WINDFROM端等,这叫做面向服务的编程思想. 发布:和网站发布也是一样的. //web ...
- C#连接Mysql数据库 MysqlHelper.cs文件
mysql.data.dll下载_c#连接mysql必要插件mysql.data.dll是C#操作MYSQL的驱动文件,是c#连接mysql必要插件,使c#语言更简洁的操作mysql数据库.当你的电脑 ...
- osm2pgsql导入duplicate key error in slim mode
This is a well known issue and one that is likely not going to be addressed any time soon. While the ...
- storm源码分析之任务分配--task assignment
在"storm源码分析之topology提交过程"一文最后,submitTopologyWithOpts函数调用了mk-assignments函数.该函数的主要功能就是进行topo ...