BZOJ 5467 Slay the Spire

  • 我的概率基础也太差了.jpg

大概就是这样,因为强化牌至少翻倍,所以打出的牌必定是全部的强化牌或者$k-1$个强化牌,然后剩余的机会打出最大的几个攻击牌。

我们对于强化牌和攻击牌分别做,并且显然,排序并不会影响答案。

$f[i][j]$表示前$i$张牌,取到$j$张,第$i$张必定取的最大强化值之积,$g[i][j]$表示前$i$张攻击牌,取到$j$张,第$i$张必定取的最大伤害和。(一般来说,应该先考虑第$i$张不必需取的最大值,但是由于那样设计状态并不能优化成$n^2$,所以只能选择第$i$张必须选的答案)

$f[i][j]=a_i\times \sum\limits_{k=j-1}^{i-1} f[k][j-1]$

$g[i][j]=C(i-1,j-1)\times b_i+\sum\limits_{k=j-1}^{i-1} g[k][j-1]$

然后剩下的就是如何计算答案了。

那么很显然,我们要求的是前$n$张排中,选择$j$个,第$n$个不必需选择的答案。

因此设$F(i,j)$表示摸到$i$张,选择$j$个的最大强化之积。那么很显然,$F(i,j)=\sum\limits_{k=i}^nf[k][j]\times C(n-k,i-j)$

同时设$G(i,j)$表示摸到$i$张,选择$j$个的最大伤害之和。那么很显然,$G(i,j)=\sum\limits_{k=i}^n g[k][j]\times C(n-k,i-j)$

同样,根据我们最初得到的结论,$ans=\sum\limits_{i=0}^{k-1}F(i,i)\times G(m-i,k-i)+\sum\limits_{i=k}^m F(i,k-1)\times G(m-i,1)$

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <iostream>
#include <bitset>
using namespace std;
#define N 3005
#define ll long long
#define mod 998244353
int f[N][N],g[N][N],n,k,a[N],b[N],m,sum[N],C[N][N];
void init()
{
for(int i=0;i<=3000;i++)
{
C[i][0]=1;
for(int j=1;j<=i;j++)C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
}
}
int F(int x,int y)
{
if(x<y)return 0;if(!y)return C[n][x];int ret=0;
for(int i=x-y+1;i<=n-y+1;i++)ret=(ret+(ll)f[y][i]*C[i-1][x-y])%mod;
return ret;
}
int G(int x,int y)
{
if(x<y)return 0;int ret=0;
for(int i=x-y+1;i<=n-y+1;i++)ret=(ret+(ll)g[y][i]*C[i-1][x-y])%mod;
return ret;
}
void solve()
{
scanf("%d%d%d",&n,&m,&k);
// memset(f,0,sizeof(f));memset(g,0,sizeof(g));
for(int i=1;i<=n;i++)
for(int j=1;j<=n-i+1;j++)
f[i][j]=g[i][j]=0;
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++)scanf("%d",&b[i]);
sort(a+1,a+n+1);sort(b+1,b+n+1);
for(int i=1;i<=n;i++)f[1][i]=a[i],sum[i]=(sum[i-1]+a[i])%mod;
for(int i=2;i<=n;i++)
{
for(int j=1;j<=n-i+1;j++)f[i][j]=(ll)a[j]*(sum[n]-sum[j]+mod)%mod;
for(int j=1;j<=n-i+1;j++)sum[j]=(sum[j-1]+f[i][j])%mod;
for(int j=n-i+2;j<=n;j++)sum[j]=sum[j-1];
}
for(int i=1;i<=n;i++)g[1][i]=b[i],sum[i]=(sum[i-1]+b[i])%mod;
for(int i=2;i<=n;i++)
{
for(int j=1;j<=n-i+1;j++)g[i][j]=((ll)b[j]*C[n-j][i-1]+sum[n]-sum[j]+mod)%mod;
for(int j=1;j<=n-i+1;j++)sum[j]=(sum[j-1]+g[i][j])%mod;
for(int j=n-i+2;j<=n;j++)sum[j]=sum[j-1];
}
int ans=0;
for(int i=0;i<m;i++)
{
if(i<k)ans=(ans+(ll)F(i,i)*G(m-i,k-i))%mod;
else ans=(ans+(ll)F(i,k-1)*G(m-i,1))%mod;
}
printf("%d\n",ans);
}
int main(){init();int T;scanf("%d",&T);while(T--)solve();return 0;}

BZOJ 5467 Slay the Spire的更多相关文章

  1. LOJ #2538. 「PKUWC 2018」Slay the Spire (期望dp)

    Update on 1.5 学了 zhou888 的写法,真是又短又快. 并且空间是 \(O(n)\) 的,速度十分优秀. 题意 LOJ #2538. 「PKUWC 2018」Slay the Spi ...

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

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

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

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

  4. [PKUWC2018] Slay the spire

    Description 现在有 \(n\) 张强化牌和 \(n\) 张攻击牌: 攻击牌:打出后对对方造成等于牌上的数字的伤害. 强化牌:打出后,假设该强化牌上的数字为 \(x\),则其他剩下的攻击牌的 ...

  5. 题解-PKUWC2018 Slay the Spire

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

  6. LOJ2538 PKUWC2018 Slay the Spire DP

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

  7. LOJ2538. 「PKUWC2018」Slay the Spire【组合数学】

    LINK 思路 首先因为式子后面把方案数乘上了 所以其实只用输出所有方案的攻击力总和 然后很显然可以用强化牌就尽量用 因为每次强化至少把下面的牌翻一倍,肯定是更优的 然后就只有两种情况 强化牌数量少于 ...

  8. PKUWC Slay The Spire

    题面链接 LOJ sol 好神啊.果然\(dp\)还是做少了,纪录一下现在的思维吧\(QAQ\). 我们首先可以发现期望是骗人的,要不然他乘的是什么xjb玩意. 其实就是要求所有方案的最优方案和. 因 ...

  9. loj2538 「PKUWC2018」Slay the Spire 【dp】

    题目链接 loj2538 题解 比较明显的是,由于强化牌倍数大于\(1\),肯定是能用强化牌尽量用强化牌 如果强化牌大于等于\(k\),就留一个位给攻击牌 所以我们将两种牌分别排序,企图计算\(F(i ...

随机推荐

  1. Play 2D games on Nexus 6P running Android N7.1.1 with Daydream View VR headset

    http://files.cnblogs.com/files/we-hjb/N6P_Android7_SBS_SF.rar

  2. tornado 模板引擎

    在tornado的模板引擎中,有两种方式,UImethod与UImodule 自定义方法 在模板中调用方法: tornado:与Django一样使用{{}},但是对于for循环之类,Django以{% ...

  3. (网页)jQuery判断checkbox是否选中的方法

    if($('#checkbox-id').is(':checked')) { // do something} if ($('#checkbox-id').attr('checked')) {    ...

  4. mysql之连接查询、联合查询、子查询

    本文内容: 连接查询 联合查询 子查询 from子查询 where子查询 exists子查询 首发日期:2018-04-11 连接查询: 连接查询就是将多个表联合起来查询,连接查询方式有内连接.外连接 ...

  5. (python)面向对象

    一.面向对象概述 要了解面向对象,就需要先了解面向过程的概念,那么什么是面向过程编程呢?最具代表性的就是C语言了,所谓面向过程编程就是在做一件事的时候,需要按步骤进行,第一步干什么,第二步干什么,这种 ...

  6. 如何在Ruby中编写微服务?

    [编者按]本文作者为 Pierpaolo Frasa,文章通过详细的案例,介绍了在Ruby中编写微服务时所需注意的方方面面.系国内 ITOM 管理平台 OneAPM 编译呈现. 最近,大家都认为应当采 ...

  7. gitolite的部署

    gitolite服务部署: 1,在git服务器端安装git并创建git用户. yum install -y git useradd git 2,生成gitolite的管理账户,这个账户也可以在git服 ...

  8. 记一次zookeeper单机伪集群分布

    zookeeper的各版本(历史版本)下载地址:http://apache.org/dist/zookeeper/ 环境>:linux 下载的zookeeper解压成3个

  9. Spring MVC HelloWorld入门及运行机制 (一)

    完整的项目案例: springmvc.zip 介绍 SpringMVC是一款Web MVC框架. 它跟Struts框架类似,是目前主流的Web MVC框架之一. 文章通过实例来介绍SpringMVC的 ...

  10. mysql 数据库 命令行的操作——对库的操作

    1.查看所有数据库 show databaese; 2.查看当前所用的数据库 show databases(): 3.切换数据库 use(数据库名): 4.创建数据库 create database ...