LOJ2538 PKUWC2018 Slay the Spire DP
不想放题面了,咕咕咕咕咕
这个期望明明是用来吓人的,其实要算的就是所有方案的最多伤害的和。
首先可以知道的是,能出强化牌就出强化牌(当然最后要留一张攻击牌出出去),且数字尽量大
所以说在强化牌数量$< K$时会打出所有强化牌和剩下的最大的攻击牌,而强化牌数量$\geq K$的时候则会打出$K-1$张强化牌和$1$张攻击牌,且它们的数字都是最大的
我们不妨计算每一种最优打出的方案存在在多少种抽取方案中。
设$f_{i,j}$表示使用$i$张强化牌,其中数值最小的牌是第$j$张时的方案的强化数值之和,$g_{i,j}$表示使用$i$张攻击牌,其中数值最小的牌是第$j$张时的方案的攻击数值之和,简单的前缀和优化DP就可以完成。处理完之后,所有抽取了$x$张强化牌和$y$张攻击牌,选择$i$张强化牌和$j$张攻击牌的方案的总伤害和就是
$$\sum\limits_k \sum\limits_l f_{i,k} \times g_{j,l} \times C_{k-1}^{x-i} \times C_{l-1}^{y-j}$$
两个理解:
①$f$和$g$中间用乘号是因为$f$中间的每一个方案和$g$中的每一个方案都可以对应产生一种抽取方式
②后面的两个组合数的意思是:对于强化牌,已经使用了$i$张,最小的是$k$,那么剩下的$x-i$张需要在剩余的$k-1$中抽取,方案数就是组合数,后面同理
那么我们枚举强化牌抽了多少张,就可以直接计算答案。
#include<bits/stdc++.h>
//This code is written by Itst
using namespace std; inline int read(){
int a = ;
bool f = ;
char c = getchar();
while(c != EOF && !isdigit(c)){
if(c == '-')
f = ;
c = getchar();
}
while(c != EOF && isdigit(c)){
a = (a << ) + (a << ) + (c ^ '');
c = getchar();
}
return f ? -a : a;
} const int MOD = , MAXN = ;
long long dp[MAXN + ][MAXN + ] , f[MAXN + ][MAXN + ] , g[MAXN + ][MAXN + ] , num[][MAXN + ] , jc[MAXN + ] , ny[MAXN + ] , N , M , K , ans; bool cmp(int a , int b){
return a > b;
} inline int poww(long long a , int b){
int times = ;
while(b){
if(b & )
times = times * a % MOD;
a = a * a % MOD;
b >>= ;
}
return times;
} signed main(){
#ifndef ONLINE_JUDGE
freopen("2538.in" , "r" , stdin);
//freopen("2538.out" , "w" , stdout);
#endif
jc[] = ;
for(long long i = ; i <= MAXN ; ++i)
jc[i] = jc[i - ] * i % MOD;
ny[MAXN] = poww(jc[MAXN] , MOD - );
for(long long i = MAXN - ; i >= ; --i)
ny[i] = ny[i + ] * (i + ) % MOD;
for(int i = ; i <= MAXN ; ++i)
dp[][i] = ;
for(int i = ; i <= MAXN ; ++i)
for(int j = ; j <= MAXN ; ++j)
dp[i][j] = (dp[i - ][j - ] + dp[i][j - ]) % MOD;
for(int i = ; i <= MAXN ; ++i)
f[][i] = ; for(int T = read() ; T ; --T){
N = read();
M = read();
K = read();
for(int i = ; i <= N ; ++i)
num[][i] = read();
sort(num[] + , num[] + N + , cmp);
for(int i = ; i <= N ; ++i)
num[][i] = read();
sort(num[] + , num[] + N + , cmp);
ans = ; for(int i = ; i <= N ; ++i)
for(int j = ; j <= N ; ++j){
f[i][j] = (1ll * f[i - ][j - ] * num[][j] + f[i][j - ]) % MOD;
g[i][j] = (g[i - ][j - ] + 1ll * (dp[i][j] - dp[i][j - ] + MOD) * num[][j] + g[i][j - ]) % MOD;
} for(int i = ; i < K ; ++i){
int sum1 = f[i][N] , sum2 = ;
for(int j = K - i ; N - j >= M - K ; ++j)
sum2 = (sum2 + 1ll * (g[K - i][j] - g[K - i][j - ] + MOD) * jc[N - j] % MOD * ny[M - K] % MOD * ny[N - j - (M - K)]) % MOD;
ans = (ans + 1ll * sum1 * sum2) % MOD;
} for(int i = K ; i < M ; ++i){
int sum1 = , sum2 = ;
for(int j = K - ; N - j >= i - (K - ) ; ++j)
sum1 = (sum1 + 1ll * (f[K - ][j] - f[K - ][j - ] + MOD) * jc[N - j] % MOD * ny[i - (K - )] % MOD * ny[N - j - (i - (K - ))]) % MOD;
for(int j = ; N - j >= M - i - ; ++j)
sum2 = (sum2 + 1ll * (g[][j] - g[][j - ] + MOD) * jc[N - j] % MOD * ny[M - i - ] % MOD * ny[N - j - (M - i - )]) % MOD;
ans = (ans + 1ll * sum1 * sum2) % MOD;
}
cout << ans << endl;
}
return ;
}
LOJ2538 PKUWC2018 Slay the Spire DP的更多相关文章
- [LOJ2538][PKUWC2018]Slay the Spire:DP
分析 学会新姿势!我们可以通过调整DP顺序来体现选取物品的优先顺序! 显然选取强化牌的最优策略是倍数从高到低,能选就选,最多选\(k-1\)张,选取攻击牌的最优策略是伤害从高到低,尽量少选,但最少选\ ...
- BZOJ.5467.[PKUWC2018]Slay the Spire(DP)
LOJ BZOJ 洛谷 哪张能力牌能乘攻击啊,太nb了叭 显然如果有能力牌,那么应该选最大的尽可能的打出\(k-1\)张. 然后下面说的期望都是乘总方案数后的,即所有情况的和.然后\(w_i\)统一用 ...
- [LOJ2538] [PKUWC2018] Slay the Spire
题目链接 LOJ:https://loj.ac/problem/2538 Solution 计数好题. 首先可以发现这题和期望没关系. 其次对于手上的一套牌,设我们有\(a\)张强化牌,那么: 如果\ ...
- 洛谷 P5299 - [PKUWC2018]Slay the Spire(组合数学+dp)
题面传送门 hot tea 啊--这种风格及难度的题放在省选 D2T1 左右还是挺喜闻乐见的罢 首先考虑对于固定的 \(m\) 张牌怎样求出最优的打牌策略,假设我们抽到了 \(p\) 张强化牌,攻击力 ...
- 【loj2538】 【PKUWC 2018】Slay the Spire dp
我们不难发现,假设抽了x张攻击牌,y张强化牌,那么肯定是打出尽可能多张的强化牌后,再开始出攻击牌(当然最少要一张攻击牌) 我们设G(i,j)表示:所有(抽到的攻击牌牌数为i,打出的攻击牌牌数为j)的方 ...
- 题解-PKUWC2018 Slay the Spire
Problem loj2538 Solution 在考场上当然要学会写暴力,考虑如果手上已经有了\(a\)张攻击牌和\(b\)张强化牌: 首先强化牌会在攻击牌之前用(废话),其次要将两种牌分别从大往小 ...
- [PKUWC2018] Slay the spire
Description 现在有 \(n\) 张强化牌和 \(n\) 张攻击牌: 攻击牌:打出后对对方造成等于牌上的数字的伤害. 强化牌:打出后,假设该强化牌上的数字为 \(x\),则其他剩下的攻击牌的 ...
- 【洛谷5299】[PKUWC2018] Slay the Spire(组合数学)
点此看题面 大致题意: 有\(n\)张强化牌\(a_i\)和\(n\)张攻击牌\(b_i\),每张牌有一个权值(强化牌的权值大于\(1\)),每张强化牌能使所有攻击牌的权值乘上这张强化牌的权值,每张攻 ...
- LOJ #2538. 「PKUWC 2018」Slay the Spire (期望dp)
Update on 1.5 学了 zhou888 的写法,真是又短又快. 并且空间是 \(O(n)\) 的,速度十分优秀. 题意 LOJ #2538. 「PKUWC 2018」Slay the Spi ...
随机推荐
- IDEA项目搭建六——使用Eureka和Ribbon进行项目服务化
一.Eureka的作用 这里先简单说明使用eureka进行业务层隔离,实现项目服务化也可以理解为微服务,我一直崇尚先实现代码再学习理论,先简单上手进行操作,eureka使用分为三块,1是服务注册中心, ...
- Flume组件汇总2
Component Interface Type Alias Implementation Class org.apache.flume.Channel memory org.apache.flume ...
- 你不可不知的Java引用类型之——软引用
定义 软引用是使用SoftReference创建的引用,强度弱于强引用,被其引用的对象在内存不足的时候会被回收,不会产生内存溢出. 说明 软引用,顾名思义就是比较"软"一点的引用. ...
- 11.1、socket连接中的粘包、精确传输问题
粘包: 发生原因: 当调用send的时候,数据并不是即时发给客户端的.而是放到了系统的socket发送缓冲区里,等缓冲区满了.或者数据等待超时了,数据才会发送,所以有时候发送太快的话,前一份数据还没有 ...
- 【js基础】创建对象的几种常见模式(工厂模式,构造函数模式,原型模式,构造原型组合模式)
一.工厂模式 缺点:没有解决对象识别的问题 优点:解决了创建多个相似对象的问题 function createPerson(name,age,job){ var o = new Object(); o ...
- PHP类多继承的替代方案Traits
概述 traits是PHP5.4新进入的特性,其目的就是解决PHP的类不能多继承的问题.Traits不是类!不能被实例化.可以理解为一组能被不同的类都能调用到的方法集合.只需要在类中使用关键词use引 ...
- [20170623]利用传输表空间恢复部分数据.txt
[20170623]利用传输表空间恢复部分数据.txt --//昨天我测试使用传输表空间+dblink,上午补充测试发现表空间设置只读才能执行impdp导入原数据,这个也很好理解.--//这样的操作模 ...
- sql 查询表格中多列重复的数据并显示该表的其他列
我们一般情况下通过分组函数group by来查询重复的列 ) R 但是查询出的结果不能显示该表的其他列 想要查询一张表中有多个列重复的数据且也要显示该表的其他列 SELECT M.* FROM [db ...
- Github API
Web API web api是网站的一部分,用于与使用非常具体的URL请求特定信息的程序交互,这种请求被称为API调用.请求的数据将以易于处理的格式(如JSON或CSV)返回:依赖于外部数据源的大多 ...
- Hbase-2.0.0_03_Hbase数据模型
1. hbase数据模型 1.1. HBase数据模型术语 Table HBase表由多行组成. Row HBase中的一行由一个行键和一个或多个列组成,列的值与这些列相关联.存储行时,按行键按字母顺 ...