有攻击牌和强化牌各 $n$ 张,强化牌可以让之后所有攻击牌攻击力乘一个大于 $1$ 的系数,攻击牌可以造成伤害

求所有“抽出 $m$ 张然后打 $k$ 张”能造成的伤害之和

$k,m,2n \leq 3000$

sol:

冷静一下,发现强化牌肯定要打完,因为一张攻击力最大的攻击牌就相当于没强化的强化牌

讨论一下抽到了几张强化牌

假设抽到了 $i$ 张强化牌,$k-i$ 张攻击牌

如果 $i < k$ 直接强化全打然后攻击就完事了,如果 $i \geq k$ 的话打最大的 $k-1$ 张强化和最大的一张攻击

由此可以 $dp$

设 $f_i$ 为 $i$ 张强化牌最多能扩的倍数,枚举当前抽到的强化牌 $j$,则

当 $i < k$ 时,$f_i = f_{i-1} + w_j \times f_j$

else, $f_i = f_i+f_{i-1}$

设 $g_i$ 为选了 $i$ 张攻击牌不翻倍的最大攻击力,枚举当前抽到的攻击牌 $j$,则

$g_i = g_{i-1} + C_{i-1}^{j-1} \times w_j + c$ (当 $i \leq (m-k+1)$ 时 $c=0$,$i>(m-k+1)$ 时 $c=g_{i-1}$)

答案就是 $\sum\limits_{i=0}^m f_i \times g_{m-i}$

第一个转移显然是按倍数从大到小排序,第二个需要把攻击力从小到大排序,

第一个转移,不管是怎么转移过来的,每张强化牌的贡献都是一样的,

第二个算每张牌贡献的时候,$c$ 标注了这张攻击牌打完之后还能不能再打别的攻击牌,如果不能打就是 $0$,能打的话要求跟他一起打的尽量大,这样转移能保证我们打的是一段尽量大的攻击牌

#include<bits/stdc++.h>
#define LL long long
#define rep(i,s,t) for(register int i = (s),i##end = (t); i <= i##end; ++i)
#define dwn(i,s,t) for(register int i = (s),i##end = (t); i >= i##end; --i)
using namespace std; const int mod = ;
inline int read()
{
int x=,f=;char ch;
for(ch=getchar();!isdigit(ch);ch=getchar())if(ch=='-')f=-f;
for(;isdigit(ch);ch=getchar())x=*x+ch-'';
return x*f;
}
bool cmp(int a, int b) { return a > b; }
LL fac[], inv[];
int T, n, m, k, ans, f[], g[], w[];
LL C(int n, int m) { return fac[n] * inv[m] % mod * inv[n - m] % mod; }
int main() {
fac[] = fac[] = inv[] = inv[] = ;
for (int i = ; i <= ; i++) {
fac[i] = fac[i - ] * i % mod;
inv[i] = ((LL)mod - mod / i) * inv[mod % i] % mod;
}
for (int i = ; i <= ; i++) inv[i] = inv[i] * inv[i - ] % mod;
T = read();
while (T--) {
n = read(), m = read(), k = read();
for (int i = ; i <= n; i++) w[i] = read();
sort(w + , w + n + , cmp);
for (int i = ; i <= max(n, m); i++) f[i] = ;
f[] = ;
for (int i = ; i <= n; i++)
for (int j = min(m, i); j >= ; j--)
if (j <= k - )
f[j] = (f[j] + (LL)f[j - ] * w[i] % mod) % mod;
else
f[j] = (f[j] + f[j - ]) % mod;
for (int i = ; i <= n; i++) w[i] = read();
sort(w + , w + n + );
for (int i = ; i <= max(n, m); i++) g[i] = ;
for (int i = ; i <= n; i++)
for (int j = min(m, i); j >= ; j--)
if (j <= m - (k - ))
g[j] = (g[j] + (LL)C(i - , j - ) * w[i] % mod) % mod;
else
g[j] = ((g[j] + g[j - ]) % mod + (LL)C(i - , j - ) * w[i] % mod) % mod;
ans = ;
for (int i = ; i <= m; i++) ans = (ans + (LL)f[i] * g[m - i] % mod) % mod;
printf("%d\n", ans);
}
return ;
}

当然比赛不会真的这么写...老老实实用两维状态前缀和优化,考后自然要选择好一点的写法

PKUSC2018 Slay The Spire的更多相关文章

  1. BZOJ 5467 Slay the Spire

    BZOJ 5467 Slay the Spire 我的概率基础也太差了.jpg 大概就是这样,因为强化牌至少翻倍,所以打出的牌必定是全部的强化牌或者$k-1$个强化牌,然后剩余的机会打出最大的几个攻击 ...

  2. LOJ #2538. 「PKUWC 2018」Slay the Spire (期望dp)

    Update on 1.5 学了 zhou888 的写法,真是又短又快. 并且空间是 \(O(n)\) 的,速度十分优秀. 题意 LOJ #2538. 「PKUWC 2018」Slay the Spi ...

  3. loj #2538. 「PKUWC2018」Slay the Spire

    $ \color{#0066ff}{ 题目描述 }$ 九条可怜在玩一个很好玩的策略游戏:Slay the Spire,一开始九条可怜的卡组里有 \(2n\) 张牌,每张牌上都写着一个数字\(w_i\) ...

  4. BZOJ.5467.[PKUWC2018]Slay the Spire(DP)

    LOJ BZOJ 洛谷 哪张能力牌能乘攻击啊,太nb了叭 显然如果有能力牌,那么应该选最大的尽可能的打出\(k-1\)张. 然后下面说的期望都是乘总方案数后的,即所有情况的和.然后\(w_i\)统一用 ...

  5. [PKUWC2018] Slay the spire

    Description 现在有 \(n\) 张强化牌和 \(n\) 张攻击牌: 攻击牌:打出后对对方造成等于牌上的数字的伤害. 强化牌:打出后,假设该强化牌上的数字为 \(x\),则其他剩下的攻击牌的 ...

  6. 题解-PKUWC2018 Slay the Spire

    Problem loj2538 Solution 在考场上当然要学会写暴力,考虑如果手上已经有了\(a\)张攻击牌和\(b\)张强化牌: 首先强化牌会在攻击牌之前用(废话),其次要将两种牌分别从大往小 ...

  7. LOJ2538 PKUWC2018 Slay the Spire DP

    传送门 不想放题面了,咕咕咕咕咕 这个期望明明是用来吓人的,其实要算的就是所有方案的最多伤害的和. 首先可以知道的是,能出强化牌就出强化牌(当然最后要留一张攻击牌出出去),且数字尽量大 所以说在强化牌 ...

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

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

  9. PKUWC Slay The Spire

    题面链接 LOJ sol 好神啊.果然\(dp\)还是做少了,纪录一下现在的思维吧\(QAQ\). 我们首先可以发现期望是骗人的,要不然他乘的是什么xjb玩意. 其实就是要求所有方案的最优方案和. 因 ...

随机推荐

  1. Apache Kudu

    Apache Kudu是由Cloudera开源的存储引擎,可以同时提供低延迟的随机读写和高效的数据分析能力.Kudu支持水平扩展,使用Raft协议进行一致性保证,并且与Cloudera Impala和 ...

  2. 学会Retrofit+OkHttp+RxAndroid三剑客的使用,让自己紧跟Android潮流的步伐

    http://blog.csdn.net/iamzgx/article/details/51607387 概括 在上一篇博客android网络框架OkHttp之get请求(源码初识) 讲解了OkHtt ...

  3. UCOS2_STM32F1移植详细过程

    源:UCOS2_STM32F1移植详细过程(三) UCOS2_STM32移植过程.系统内核.事件描述(汇总)

  4. 七 、linux正则表达式

    为处理大量的字符串而定义的一套规则和方法 1)linux正则表达式以行为单位处理 2)alians grep = “grep –color=auto”,让匹配的内容显示颜色 3)注意字符集,expor ...

  5. 12.常见模块time、json模块

    1.time模块 import time #python中最基本的时间模块 time.time() #时间戳 (1970年1月1日00:00:00后经过的浮点秒数) time.localtime(ti ...

  6. oracle 启动数据库与监听器

    1.oracle 启动数据库与监听器 1)启动数据库 oracle用户进去 oracle/oracle sqlplus / as sysdba 然后startup 退出,然后启动监听进程 2)启动监听 ...

  7. SpringMVC实现AJax以及RestFull风格

    RestFull风格就是url路径中不能出现?不能带参数,如https://www.baidu.com/user/item/1234这个格式,也叫url资源定位 1.需要在web.xml中开启put, ...

  8. 【bzoj1345】[Baltic2007]序列问题Sequence

    题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=1345 因为合并的花费是较大数的权值,所以每个数肯定是和附近的小数合并完后才与大数合并, ...

  9. 【bzoj2423】最长公共子序列[HAOI2010](dp)

    题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2423 题目大意:求两个字符串的最长公共子序列长度和最长公共子序列个数. 这道题的话,对于 ...

  10. ElasticSearch入门常用命令

    基于开源项目MyAlice智能客服学习ElasticSearch https://github.com/hpgary/MyAlice/wiki/%E7%AC%AC01%E7%AB%A0%E5%AE%8 ...