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 ...
随机推荐
- web全栈架构师[笔记] — 01 ECMAScript6新特性
ES6新特性 一.变量 var:重复定义不报错:没有块级作用域:不能限制修改 let:变量,不能重复定义,有块级作用域 const:常量,不能重复定义,有块级作用域 二.函数/参数 箭头函数——简写: ...
- Java抽象类和接口的比较
一个软件设计的好坏,我想很大程度上取决于它的整体架构,而这个整体架构其实就是你对整个宏观商业业务的抽象框架,当代表业务逻辑的高层抽象层结构 合理时,你底层的具体实现需要考虑的就仅仅是一些算法和一些具体 ...
- Loadrunner 脚本开发-soap_request函数介绍及WebService接口测试
脚本开发- soap_request函数介绍及WebService接口测试 by:授客 QQ:1033553122 函数介绍 soap_request 函数执行一个SOAP请求 函数原型 int so ...
- PullToRefreshGridView上拉刷新,下拉加载
PullToRefreshGridView上拉刷新,下拉加载 布局: <?xml version="1.0" encoding="utf-8"?> ...
- 项目开发常见字符串处理模型-strstr-while/dowhile模型
strstr-whiledowhile模型用于在母字符串中查找符合特征的子字符串. c语言库提供了strstr函数,strstr函数用于判断母字符串中是否包含子字符串,包含的话返回子字符串的位置指针, ...
- (网页)AngularJS中【Error: [$rootScope:inprog]】的解决办法(转)
转自CSDN: Error: [$rootScope:inprog] http://errors.angularjs.org/1.5.8/$rootScope/inprog?p0=%24apply 如 ...
- wx python 基本控件
一.静态文本控件 wx.StaticText(parent, id, label, pos=wx.DefaultPosition, size=wx.DefaultSize, style=0, n ...
- JavaScript大杂烩7 - 理解内置集合
JavaScript内置了很多对象,简单的类型如String,Number,Boolean (相应的"值类型"拥有相同的方法),复杂一点的如Function,Object,Arra ...
- 我的简历 PHP Java C# 技术总监
石先生 ID:303321266 目前正在找工作 13611326258 hr_msn@163.com 男|32 岁 (1985/08/06)|现居住北京-海淀区|12年工作经验 ...
- C# 异步编程4 async与await 异步程序开发
随着C#异步程序开发系列的深入,你会发现编写异步程序越发简单.事物的发展就是这样的规律,从简单到复杂再到简单. 在C# 5.0中我们可以通过async与await关键字实现快捷的异步程序开发,如下: ...