有攻击牌和强化牌各 $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. getchar,scanf以及缓冲区

    getchar()是stdio.h中的库函数,它的作用是从stdin流中读入一个字符,也就是说,如果stdin有数据的话不用输入它就可以直接读取了.getch()和getche()是conio.h中的 ...

  2. JavaScript:基础扩展(1)——JSON

    JavaScript:扩展知识(1)——JSON 理解: 关于 JSON,最重要的是要理解它是一种数据格式,不是一种编程语言.虽然具有相同的语法形式,但 JSON 并不从属于 JavaScript.而 ...

  3. mtime、atime、ctime基本解释

    不罗嗦 Access time.Modify time.Change time,也就是访问时间.修改时间和状态时间. >修改时间:文件的内容被最后一次修改的时间,我们经常用的ls -l命令显示出 ...

  4. 【转载】iptables、tc和ip命令

    2.3 CommandListener中的命令 CL一共定义了11个命令,这些命令充分反映了Netd在Android系统中网络管理和控制方面的职责.本节首先介绍Linux系统中常用的三个网络管理工具, ...

  5. Windows下MarialDB使用

    命令行控制启动和关闭:mysqld --console     #这样启动ctrl+c即为关闭 启动:双击mysqld.exe即可   #此为后台启动 关闭:mysqladmin -uroot -pr ...

  6. 跨平台移动开发_PhoneGap API Camera 使用摄像头采集照片.

    camera对象提供对设备默认摄像头应用程序的访问. 程序运行效果 相关代码 <!DOCTYPE html> <html> <head> <title> ...

  7. mongodb中的__v字段

    "__v"是"versionKey"的简写,当每一个文档由mongoose创建时就会自动添加,代表这该文档的版本,此属性可配置修改,默认为"__v&q ...

  8. linux下firefox显示中文乱码的问题

    只需要yum install "@Chinese Support" 然后注销,再登录一下,刷新浏览器就可以正常显示中文了,当然前提是浏览器的字符编码为utf-8以及默认显示中文,这 ...

  9. python global

    如果想在函数内部改变函数外的变量值,用global语句完成: 在不传该变量值入函数的情况下要改变它的值: >>> a = 3 >>> def f(): ... gl ...

  10. 阿里云分布式缓存OCS与DB之间的数据一致性

    [分布式系统的数据一致性问题]   OCS概要介绍 据AlertSite网络分析公司表示,Facebook的响应时间在2010年平均为1秒钟,到2011年中期已提高到了0.73秒.对比来看,响应时间占 ...