[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$个强化牌,然后剩余的机会打出最大的几个攻击 ...
随机推荐
- easyUI dialog打开对话框,显示列表数据,选取一条数据操作后赋值给父窗口 resultMap声明为全局,生成getset方法
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" ...
- suse11 安装 python3.6 python3 安装步骤
首先需要去网上下载Python-3.6.4.tgz,libopenssl-devel-0.9.8j-2.1.x86_64.rpm zlib-devel-1.2.7-3.14.x86_64.rpm li ...
- C语言fprintf, fwrite, fscanf, fread混用问题
int main(int argc, const char * argv[]) { // insert code here... FILE * fp = fopen("test.txt&qu ...
- winform窗体退出
winform主窗体退出需要在FormClosing事件里写入程序退出代码,防止程序明明退出了,而程序进程还没杀掉: private void FormMain_FormClosing(object ...
- 宝塔Linux面板 - 7月4日更新 - 5.9免费版
官网地址:https://www.bt.cn/bbs/thread-1186-1-1.html 安装要求: Python版本: 2.6/2.7(安装宝塔时会自动安装) 内存:128M以上,推荐512M ...
- STM32 HAL库的使用心得
1.I2C函数中HAL_I2C_Mem_Write和HAL_I2C_Master_Transmit有啥区别?{ 使用HAL_I2C_Mem_Write等于 先使用HAL_I2C_Master_Tran ...
- spak数据倾斜解决方案
数据倾斜解决方案 数据倾斜的解决,跟之前讲解的性能调优,有一点异曲同工之妙. 性能调优中最有效最直接最简单的方式就是加资源加并行度,并注意RDD架构(复用同一个RDD,加上cache缓存).相对于前面 ...
- 自定义Token的CAS登录
工作中实际遇到的需求,我们有一个旧系统,用了CAS的单点登录,现在有一个外部系统,准备从它那里单点进来,这个外部系统提供了一个token参数来标记这是哪一个用户,我们用他们提供的方式解析出对应的用户, ...
- 把纯C的动态库代码改造成C++版的
近期想把一份纯C的跨Win/Linux的动态库工程代码改成支持C++编译器,这样用C++写起代码来比较顺手.要点是保证动态库的ABI一致性,既导出接口不能改变. 主要的改动有: 1.把.c后缀名换成. ...
- 《Java性能调优》学习笔记(1)
性能的参考指标 执行时间 -- 从代码开始运行到结束的时间 CPU时间 -- 函数或者线程占用CPU的时间 内存分配 -- 程序在运行时占用内存的情况 磁盘吞吐量 -- 描述IO的使用情况 网络吞吐量 ...