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. git 入门教程之版本管理

    版本管理 背景 在上一节中我们已经成功创建版本库并且已经添加test.txt等文件,这一节我们继续讲解如何进行版本控制. 首先我们先查看test.txt 文件有什么内容吧! # 查看文件内容 $ ca ...

  2. JavascriptDom编程艺术(笔记)

    如果想快速学习dom的话,建议去菜鸟教程,比较浅显易懂,实战性较强.我是看纸质的书,主要是花钱,心疼,所以看完,容易记住. 1.重点: .变量 -.var修饰 -.赋值,用=号,例如ver age = ...

  3. 《node.js权威指南》读书笔记

    第一章 node.js介绍 非阻塞型I/O机制 当在访问数据库取得搜索结果的时候,在开始访问数据库之后,数据库返回结果之前,存在一段等待时间. 在传统的单线程处理机制中,在执行了访问数据库的代码之后, ...

  4. Microsoft.AspNet.Identity 重置密码

    重置密码:先生成重置密码的Token,然后调用ResetPassword方法重置密码,密码要符合规则.. ApplicationUserManager UserManager => _userM ...

  5. List删除

    使用for循环,倒序删除: ; i >= ; i--) { var item = list[i]; ") { list.Remove(item); } }

  6. .svn文件夹特别大

    一个项目通过svn管理,迭代开发一年之后,.svn目录达到20G或更大,对于SSD硬盘来说是非常占用空间的,经过我的尝试,可以使用tortoiseSVN自带的cleanup为文件夹瘦身. 操作方法: ...

  7. Linux下memcache编译安装与基本使用

    memcache是一套分布式的高速缓存系统,特点为key-value 存储 一.在 linux 编译安装memcache.redis等,需要 gcc,make,cmake,autoconf,libto ...

  8. GitHub-版本管理

    参考博文:廖雪峰Git教程 1. 管理修改 现在,假定你已经完全掌握了暂存区的概念.下面,我们要讨论的就是,为什么Git比其他版本控制系统设计得优秀,因为Git跟踪并管理的是修改,而非文件. 你会问, ...

  9. Vue学习之路7-v-on指令学习之简单事件绑定

    前言 在JavaScript中任何一个DOM元素都有其自身存在的事件对象,事件对象代表事件的状态,比如事件在其中发生的元素.键盘按键的状态.鼠标的位置和鼠标按钮的状态等.事件通常与函数结合使用,函数不 ...

  10. C语言 汉诺塔问题

    //凯鲁嘎吉 - 博客园 http://www.cnblogs.com/kailugaji/ 汉诺塔是由三根杆子A,B,C组成的.A杆上有n个(n>1)穿孔圆盘,盘的尺寸由下到上依次变小.要求按 ...