Description

现在有 \(n\) 张强化牌和 \(n\) 张攻击牌:

  1. 攻击牌:打出后对对方造成等于牌上的数字的伤害。
  2. 强化牌:打出后,假设该强化牌上的数字为 \(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的更多相关文章

  1. BZOJ.5467.[PKUWC2018]Slay the Spire(DP)

    LOJ BZOJ 洛谷 哪张能力牌能乘攻击啊,太nb了叭 显然如果有能力牌,那么应该选最大的尽可能的打出\(k-1\)张. 然后下面说的期望都是乘总方案数后的,即所有情况的和.然后\(w_i\)统一用 ...

  2. 题解-PKUWC2018 Slay the Spire

    Problem loj2538 Solution 在考场上当然要学会写暴力,考虑如果手上已经有了\(a\)张攻击牌和\(b\)张强化牌: 首先强化牌会在攻击牌之前用(废话),其次要将两种牌分别从大往小 ...

  3. LOJ2538 PKUWC2018 Slay the Spire DP

    传送门 不想放题面了,咕咕咕咕咕 这个期望明明是用来吓人的,其实要算的就是所有方案的最多伤害的和. 首先可以知道的是,能出强化牌就出强化牌(当然最后要留一张攻击牌出出去),且数字尽量大 所以说在强化牌 ...

  4. [LOJ2538] [PKUWC2018] Slay the Spire

    题目链接 LOJ:https://loj.ac/problem/2538 Solution 计数好题. 首先可以发现这题和期望没关系. 其次对于手上的一套牌,设我们有\(a\)张强化牌,那么: 如果\ ...

  5. 【洛谷5299】[PKUWC2018] Slay the Spire(组合数学)

    点此看题面 大致题意: 有\(n\)张强化牌\(a_i\)和\(n\)张攻击牌\(b_i\),每张牌有一个权值(强化牌的权值大于\(1\)),每张强化牌能使所有攻击牌的权值乘上这张强化牌的权值,每张攻 ...

  6. [LOJ2538][PKUWC2018]Slay the Spire:DP

    分析 学会新姿势!我们可以通过调整DP顺序来体现选取物品的优先顺序! 显然选取强化牌的最优策略是倍数从高到低,能选就选,最多选\(k-1\)张,选取攻击牌的最优策略是伤害从高到低,尽量少选,但最少选\ ...

  7. 洛谷 P5299 - [PKUWC2018]Slay the Spire(组合数学+dp)

    题面传送门 hot tea 啊--这种风格及难度的题放在省选 D2T1 左右还是挺喜闻乐见的罢 首先考虑对于固定的 \(m\) 张牌怎样求出最优的打牌策略,假设我们抽到了 \(p\) 张强化牌,攻击力 ...

  8. loj #2538. 「PKUWC2018」Slay the Spire

    $ \color{#0066ff}{ 题目描述 }$ 九条可怜在玩一个很好玩的策略游戏:Slay the Spire,一开始九条可怜的卡组里有 \(2n\) 张牌,每张牌上都写着一个数字\(w_i\) ...

  9. BZOJ 5467 Slay the Spire

    BZOJ 5467 Slay the Spire 我的概率基础也太差了.jpg 大概就是这样,因为强化牌至少翻倍,所以打出的牌必定是全部的强化牌或者$k-1$个强化牌,然后剩余的机会打出最大的几个攻击 ...

随机推荐

  1. win10更新永久关闭

    最烦开发的时候windows来个更新 http://www.ghost580.com/win10/2016-10-21/17295.html

  2. SecureCRT两步验证自动登录脚本

    简介 用于解决 Google Authenticator 的两步验证登录.涉及到密码,不建议脚本保存到公共环境. 安装oathtool Mac $ brew install oath-toolkit ...

  3. js中树结构根据条件查找节点返回节点路径的一些思路

    今天在项目中遇到一个问题,需要根据数据库中记录的树结构节点id获取该记录所在目录节点的路径. 大致想法,首先定义变量保存当前路径,然后递归遍历该树节点,在遍历的过程中将遍历到的节点加入到当前路径中,找 ...

  4. zabbix 自带监控项报性能问题解决方法

    类似报警信息为:Zabbix discoverer processes more than 75% busy 解决方法:修改zabbix_server配置 原因:每个discovery任务在一定时间内 ...

  5. hdu 4370

    这个题说实话我没看出来,我看的别人的博客 https://blog.csdn.net/u013761036/article/details/39377499 这个人讲的很清楚,可以直接去看他的 题目给 ...

  6. EmguCV使用Stitcher类来拼接图像

    using System; using System.Windows; using System.Collections.Generic; using System.ComponentModel; u ...

  7. 我所理解的Android组件化之通信机制

    之前写过一篇关于Android组件化的文章,<Android组件化框架设计与实践>,之前没看过的小伙伴可以先点击阅读.那篇文章是从实战中进行总结得来,是公司的一个真实项目进行组件化架构改造 ...

  8. elasticSearch新认知

    之前已经学习使用过ElasticSearch的使用,今天补充巩固一下... 上一次的环境是在 linux下使用 EalsticSearch(安装教程详见:https://www.cnblogs.com ...

  9. Cannot load php5apache2_4.dll into server

    配置PHP开发环境的时候,当进行到在Apache的httpd.conf文件中配置加载PHP模块时发生如下错误 httpd: Syntax error on line 185 of D:/wamp/Ap ...

  10. 微信小程序的概要

    微信小程序的概要 学习小程序要了解一下什么事小程序,小程序开发前需要做哪些准备,微信小程序开发工具的使用,小程序中的目录结构解析,视图和渲染,事件. 小程序的配置详解,小程序的生命周期与app对象的使 ...