[PKUWC2018] Slay the spire
Description
现在有 \(n\) 张强化牌和 \(n\) 张攻击牌:
- 攻击牌:打出后对对方造成等于牌上的数字的伤害。
- 强化牌:打出后,假设该强化牌上的数字为 \(x\),则其他剩下的攻击牌的数字都会乘上 \(x\)。保证强化牌上的数字都大于 1。
现在等概率地从这 \(2n\) 张卡中抽出 \(m\) 张,并且按最优策略打出 \(k\) 张,问期望能造成多少伤害。
Solution
第一这是披着期望皮的计数题
第二最优策略肯定是能打强化牌就打强化牌,最后剩下一张攻击牌再打
既然是计数题那我们就要算出每种方案造成的伤害值然后加起来就行了
设 \(f(i,j,0/1)\) 表示前 \(i\) 张强化牌用 $j $ 张,第 \(i\) 张用不用的所有方案的乘积的和,\(g(i,j,0/1)\) 表示前 \(i\) 张攻击牌用 \(j\) 张,第 \(i\) 张用不用的所有方案的和的和
那么有转移 \(f(i,j,0)=f(i-1,j,0)+f(i-1,j,1),f(i,j,1)=f(i,j-1,0)\cdot a[i]\)
\(g(i,j,0)=g(i-1,j,0)+g(i-1,j,1),g(i,j,1)=g(i,j-1,0)+b[i]\cdot C_{i-1}^{j-1}\)
再设 \(F(i,j)\) 表示选出 \(i\) 张强化牌,用了 \(j\) 张的所有方案的乘积的和,\(G(i,j)\) 表示选出 \(i\) 张攻击牌,用了 \(j\) 张的所有方案的和的和。
那么显然有 \(ans=\sum\limits_{i=0}^m \begin{cases}F(i,i)\times G(m-i,m-i)\;\;(i<k)\\F(i,k-1)\times G(m-i,1)\;\;(i\ge k)\end{cases}\)
而 \(F,G\) 也可以通过 \(f,g\) 来求出来,可以枚举断点,即用的第 \(j\) 张是原序列的第 \(x\) 张,那么因为选择的是最优策略,原序列的前 \(x\) 张中一定不多不少选出来了 \(j\) 张,那剩下的 \(i-j\) 张就要从 \(x+1\sim n\) 中选出来,拿组合数算一下就行了。具体就是 \(F(i,j)=\sum\limits_{x=j}^{n-(i-j)} f(x,j,1)\times C_{n-x}^{i-j}\)
发现求这个 \(F,G\) 是 \(O(n^3)\) 的并不能过去。但是我们也没有必要求出所有的 \(F,G\) 。只求出需要求的那 \(O(n)\) 项即可。
Code
LOJ格式化代码好丑
#include<bits/stdc++.h>
using std::min;
using std::max;
using std::swap;
using std::vector;
typedef double db;
typedef long long ll;
#define pb(A) push_back(A)
#define pii std::pair<int,int>
#define all(A) A.begin(),A.end()
#define mp(A,B) std::make_pair(A,B)
#define int long long
const int N=3005;
const int mod=998244353;
#define inv(x) ksm(x,mod-2)
int a[N],b[N];
int n,m,k,C[N][N];
int f[N][N][2],g[N][N][2];
int getint(){
int X=0,w=0;char ch=getchar();
while(!isdigit(ch))w|=ch=='-',ch=getchar();
while( isdigit(ch))X=X*10+ch-48,ch=getchar();
if(w) return -X;return X;
}
void init(int n){
C[0][0]=1;
for(int i=1;i<=n;i++){
C[i][0]=1;
for(int j=1;j<=i;j++)
C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
}
}
int F(int x,int y){
int ans=0;
for(int i=y;i<=n;i++)
(ans+=f[i][y][1]*C[n-i][x-y]%mod)%=mod;
return ans;
}
int G(int x,int y){
if(!x) return 0;
int ans=0;
for(int i=y;i<=n;i++)
(ans+=g[i][y][1]*C[n-i][x-y]%mod)%=mod;
return ans;
}
void solve(){
n=getint(),m=getint(),k=getint();
for(int i=1;i<=n;i++) a[i]=getint();
for(int i=1;i<=n;i++) b[i]=getint();
memset(f,0,sizeof f);memset(g,0,sizeof g);
std::sort(a+1,a+1+n),std::sort(b+1,b+1+n);
std::reverse(a+1,a+1+n),std::reverse(b+1,b+1+n);
if(k==1){
int sum=0;
for(int i=1;i<=n;i++){
if(2*n-i+1<m) break;
(sum+=b[i]*C[2*n-i][m-1]%mod)%=mod;
} printf("%lld\n",sum);return;
} f[0][0][1]=1;
for(int i=1;i<=n;i++){
for(int j=0;j<=i;j++){
f[i][j][0]=(f[i-1][j][0]+f[i-1][j][1])%mod;
g[i][j][0]=(g[i-1][j][0]+g[i-1][j][1])%mod;
if(j) f[i][j][1]=f[i][j-1][0]*a[i]%mod;
if(j) g[i][j][1]=(g[i][j-1][0]+b[i]*C[i-1][j-1]%mod)%mod;
}
} int ans=0;
for(int i=0;i<=m and i<=n;i++){
if(m-i>n) continue;
if(i<k) (ans+=F(i,i)*G(m-i,k-i)%mod)%=mod;
else (ans+=F(i,k-1)*G(m-i,1)%mod)%=mod;
} printf("%lld\n",ans);
}
signed main(){
init(3000);
int T=getint();
while(T--) solve();
return 0;
}
[PKUWC2018] Slay the spire的更多相关文章
- BZOJ.5467.[PKUWC2018]Slay the Spire(DP)
LOJ BZOJ 洛谷 哪张能力牌能乘攻击啊,太nb了叭 显然如果有能力牌,那么应该选最大的尽可能的打出\(k-1\)张. 然后下面说的期望都是乘总方案数后的,即所有情况的和.然后\(w_i\)统一用 ...
- 题解-PKUWC2018 Slay the Spire
Problem loj2538 Solution 在考场上当然要学会写暴力,考虑如果手上已经有了\(a\)张攻击牌和\(b\)张强化牌: 首先强化牌会在攻击牌之前用(废话),其次要将两种牌分别从大往小 ...
- LOJ2538 PKUWC2018 Slay the Spire DP
传送门 不想放题面了,咕咕咕咕咕 这个期望明明是用来吓人的,其实要算的就是所有方案的最多伤害的和. 首先可以知道的是,能出强化牌就出强化牌(当然最后要留一张攻击牌出出去),且数字尽量大 所以说在强化牌 ...
- [LOJ2538] [PKUWC2018] Slay the Spire
题目链接 LOJ:https://loj.ac/problem/2538 Solution 计数好题. 首先可以发现这题和期望没关系. 其次对于手上的一套牌,设我们有\(a\)张强化牌,那么: 如果\ ...
- 【洛谷5299】[PKUWC2018] Slay the Spire(组合数学)
点此看题面 大致题意: 有\(n\)张强化牌\(a_i\)和\(n\)张攻击牌\(b_i\),每张牌有一个权值(强化牌的权值大于\(1\)),每张强化牌能使所有攻击牌的权值乘上这张强化牌的权值,每张攻 ...
- [LOJ2538][PKUWC2018]Slay the Spire:DP
分析 学会新姿势!我们可以通过调整DP顺序来体现选取物品的优先顺序! 显然选取强化牌的最优策略是倍数从高到低,能选就选,最多选\(k-1\)张,选取攻击牌的最优策略是伤害从高到低,尽量少选,但最少选\ ...
- 洛谷 P5299 - [PKUWC2018]Slay the Spire(组合数学+dp)
题面传送门 hot tea 啊--这种风格及难度的题放在省选 D2T1 左右还是挺喜闻乐见的罢 首先考虑对于固定的 \(m\) 张牌怎样求出最优的打牌策略,假设我们抽到了 \(p\) 张强化牌,攻击力 ...
- loj #2538. 「PKUWC2018」Slay the Spire
$ \color{#0066ff}{ 题目描述 }$ 九条可怜在玩一个很好玩的策略游戏:Slay the Spire,一开始九条可怜的卡组里有 \(2n\) 张牌,每张牌上都写着一个数字\(w_i\) ...
- BZOJ 5467 Slay the Spire
BZOJ 5467 Slay the Spire 我的概率基础也太差了.jpg 大概就是这样,因为强化牌至少翻倍,所以打出的牌必定是全部的强化牌或者$k-1$个强化牌,然后剩余的机会打出最大的几个攻击 ...
随机推荐
- Unity自动切割动画
最近在开发项目时,需要处理大量的动画,于是就网上查找资料,然后写了这么编辑器工具: 就是在模型导入时,根据配置文件自动切割动画. 首先我们需要封装两个类:一个模型类和一个动画类 public clas ...
- Java Web程序开发链接MySQL数据库
显示错误:Access denied for user ''@'localhost' (using password: YES) 保证URL中没有空格 尝试用MySQL本地命令行登陆 显示错误:The ...
- 【CF486E】LIS of Sequence题解
[CF486E]LIS of Sequence题解 题目链接 题意: 给你一个长度为n的序列a1,a2,...,an,你需要把这n个元素分成三类:1,2,3: 1:所有的最长上升子序列都不包含这个元素 ...
- idea 新建项目上传至git(coding)
一.新建项目 1.改为git版本 2.出现如下框 选择Git 3.新建一个.gitignore file (Git) 4.勾掉一些不需要的 5.出现如下框 5.1.如果不知道.gitignore fi ...
- Python爬取淘宝店铺和评论
1 安装开发需要的一些库 (1) 安装mysql 的驱动:在Windows上按win+r输入cmd打开命令行,输入命令pip install pymysql,回车即可. (2) 安装自动化测试的驱动s ...
- SQL语言基础学习
9.26.对之前学习的知识进行一下梳理,同时结合所查资料对知识进行一次整合
- 【sql注入】浅谈JSP安全开发之SQL注入
[sql注入]浅谈JSP安全开发之SQL注入 本文转自:i春秋社区 前言不管是用什么语言编写WEB应用程序,他们都或多或少有一些地方存在漏洞.如果你想知道漏洞的运行原理,和防御方案,那么请看完本篇文章 ...
- IM群聊消息的已读回执功能该怎么实现?
本文引用了架构师之路公众号作者沈剑的文章,内容有改动,感谢原作者. 1.前言 我们平时在使用即时通讯应用时候,每当发出一条聊天消息,都希望对方尽快看到,并尽快回复,但对方到底有没有真的看到?我却并不知 ...
- Android 代码混淆配置总结
一.前言 为何需要混淆呢?简单的说,就是将原本正常的项目文件,对其类,方法,字段,重新命名,a,b,c,d,e,f…之类的字母,达到混淆代码的目的,这样反编译出来,结构乱糟糟的,看了也头大. 另外说明 ...
- Ubuntu16.04设置静态ip
给Ubuntu系统配置一个静态IP ,方法如下 : 1. sudo vi /etc/network/interfaces (本人更推荐使用 sudo gedit /etc/network/inter ...