$ \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. Ubantu下安装adobe flash player插件

    用火狐看视频,要打开Adobe官网下载xxxx,太麻烦. 可以在Terminal下输入: apt-get install flashplugin-nonfree 好了.

  2. TreeView的异步延时加载

    TreeView的延时加载 在使用TreeView控件的时候,如果数据量太大,这个TreeView控件加载会很慢,有时甚至加载失败, 为了更好的使用TreeView控件加载大量的数据,采用异步延迟加载 ...

  3. Make Cents

    Every year, an elephant qualifies to the Arab Collegiate Programming Competition. He graduated this ...

  4. MYSQL中str_to_date函数的用法

    str_to_date(str,format) 函数的用法 str_to_date函数将str转化为日期型的数据,format表示转化后的格式. format参数格式: 常用: %Y  年 %m  月 ...

  5. accept巨坑

    在做node.js时, 我们要把一个资源发送回前端,需要用到以下一句: res.setHeader('Content-Type', mime ); mime,全称即Multipurpose Inter ...

  6. Bootstrap 概览

    目录1.移动设备2.响应式图片3.Normalize4.Containers 1.移动设备在Bootstrap 3中,我们重写了整个框架,使其一开始就是对移动设备友好的.这次不是简单的增加一些可选的针 ...

  7. docker下 zookeeper集群

    首先创建所需的文件夹 mkdir -p /data/{data1,data2,data3} mkdir -p /data/{datalog1,datalog2,datalog3} docker-com ...

  8. JSP页面使用EL表达式出现的问题:javax.el.PropertyNotFoundException: Property 'ID' not found on type java.lang.Str

    问题描述: 1. 后台返回到JSP前台的的list,在jsp页面使用EL表达式遍历时出现如下问题:javax.el.PropertyNotFoundException: Property 'ID' n ...

  9. GPS通讯协议协议(NMEA0183)

    一.简介 GPS(全球定位系统)接收机与手持机之间的数据交换格式一般都由生产厂商缺省定制,其定义内容普通用户很难知晓,且不同品牌.不同型号的GPS接收机所配置的控制应用程序也因生产厂家的不同而不同.所 ...

  10. 类操作,removeClass&addClass

    // 添加类 function addClass(node,className){                 var reg=new RegExp("\\b"+classNa ...