点此看题面

大致题意: 有\(n\)张强化牌\(a_i\)和\(n\)张攻击牌\(b_i\),每张牌有一个权值(强化牌的权值大于\(1\)),每张强化牌能使所有攻击牌的权值乘上这张强化牌的权值,每张攻击牌造成的伤害等于这张攻击牌的权值。现在,以等概率抽出\(m\)张牌,并以最优策略使用其中至多\(k\)张牌造成最大的伤害。求所有情况下,造成伤害总和。

前言

感觉最近肝了好久的文化课,居然思维水平不但没降,还有了点提升?

没想到居然能不看题解自己把这道题做出来,虽然\(WA\)了一次,但还算是有进步了吧!

何为最优策略

这道题看似毫无头绪,因此,我们先要好好推一推性质。

假设现在我们已经选好了\(m\)张牌,那么最优策略是什么?

首先,如果我们已经确定要用\(x\)张强化牌和\(y\)张攻击牌,那么根据贪心的想法,肯定是先使用权值最大的\(x\)张强化牌,再使用权值最大的\(y\)张攻击牌。

因此我们把\(a\)和\(b\)分别从大到小排序。

同时,同样依据贪心,我们可以知道答案就是强化牌的乘积乘上攻击牌之和

然后我们考虑,在什么情况下,把第\(y\)张攻击牌换成第\(x+1\)张强化牌,与原先答案相比不会变劣。

原先答案是:

\[\prod_{i=1}^xa_i\cdot\sum_{i=1}^y b_i
\]

变化后的答案是:

\[\prod_{i=1}^{x+1}a_i\cdot\sum_{i=1}^{y-1}b_i
\]

则两式相减,即为答案的变化量,也就是:

\[(a_{x+1}-1)\cdot(\prod_{i=1}^xa_i\cdot\sum_{i=1}^{y-1}b_i)-(\prod_{i=1}^xa_i)\cdot b_y
\]

当变化后答案不变劣,说明变化量\(\ge 0\),即:

\[(a_{x+1}-1)\cdot(\prod_{i=1}^xa_i\cdot\sum_{i=1}^{y-1}b_i)\ge(\prod_{i=1}^xa_i)\cdot b_y
\]

我们把式子中的\(\prod_{i=1}^xa_i\)去掉,就得到:

\[(a_{x+1}-1)\cdot(\sum_{i=1}^{y-1}b_i)\ge b_y
\]

由于题目中说明,强化牌权值大于\(1\),所以\(a_{x+1}-1\ge 1\)。

而在\(y>1\)时,因为\(b\)数组经过了从大到小排序,所以\(\sum_{i=1}^{y-1}b_i\)肯定大于等于\(b_y\)。

所以我们可以发现,在\(y>1\)时,\((a_{x+1}-1)\cdot(\sum_{i=1}^{y-1}b_i)\ge b_y\)是始终成立的。

也就是说,在保有至少一张攻击牌的前提下,肯定是尽量选择强化牌会更优

这么一来,这道题一下就可做得多了。

预处理

在正式开始解题之前,我们还需要进行预处理,定义几个变量。

设\(f_{i,j,0}\)表示在前\(i\)张强化牌中选择\(j\)张第\(i\)张被选中的所有情况下,这\(j\)张牌的乘积之和,\(g_{i,j,0}\)表示在前\(i\)张攻击牌中选择\(j\)张第\(i\)张被选中的所有情况下,这\(j\)张牌的和之和

同时,定义\(f_{i,j,1}=\sum_{x=1}^if_{x,j,0},g_{i,j,1}=\sum_{x=1}^ig_{x,j,0}\)来辅助转移。

则不难发现,有转移方程:

\[f_{i,j,0}=a_i\cdot f_{i-1,j-1,1}
\]

\[f_{i,j,1}=f_{i,j,0}+f_{i-1,j,1}
\]

\[g_{i,j,0}=b_i\cdot C_{i-1,j-1}+g_{i-1,j-1,1}
\]

\[g_{i,j,1}=g_{i,j,0}+g_{i-1,j,1}
\]

注意,\(g_{i,j,0}\)的转移中,\(C_{i-1,j-1}\)表示在\(i-1\)个数中选择\(j-1\)个数的方案,即从\(g_{i-1,j-1,1}\)转移到\(g_{i,j,0}\)共有\(C_{i-1,j-1}\)种情况,而每种情况卡牌权值和加上了\(b_i\),就相当于共加上了\(b_i\cdot C_{i-1,j-1}\)。

至于这些东西究竟有什么用,待会儿你就会知道了。

组合数学

接下来,就是分类讨论+推式子啦。

第一类:当\(m\)张牌中,强化牌的数量小于\(k-1\)张时。

此时必然是选上所有的强化牌,然后选上权值最大的一些攻击牌。

不难发现,其实等于\(k-1\)张时也符合这一类情况的操作方案,但为了方便起见,我们把等于\(k-1\)的情况放入另一类情况中中。

对于这一种情况,我们枚举\(i,j\)分别表示强化牌有\(i\)张最后被选中的攻击牌是第\(j\)张

在强化牌中选择\(i\)张的所有合法情况下的乘积之和,其实就是\(f_{n,i,1}\)。

而强化牌中选择\(i\)张,攻击牌中就要选择\(k-i\)张,又由于最后被选中的攻击牌是第\(j\)张,所以所有合法情况下攻击牌的和之和,其实就是\(g_{j,k-i,0}\)。

而若要最终选出的\(k\)张牌是这\(k\)张牌,就剩余\(m-k\)张牌就需要满足:

  • 不存在强化牌。
  • 所有攻击牌都必须在第\(j\)张之后,否则选这张攻击牌肯定比选第\(j\)张优。

因此方案数就是\(C_{n-j}^{m-k}\)。

总结一下,就是枚举\(i,j\),然后每次答案加上\(f_{n,i,1}\cdot g_{j,k-i,0}\cdot C_{n-j}^{m-k}\)。

第二类:当\(m\)张强化牌中,强化牌的数量大于等于\(k-1\)时。

此时必然是选上权值最大的\(k-1\)张强化牌,然后选上权值最大的一张攻击牌。

对于这一种情况,我们枚举\(i,j\)分别表示最后被选中的强化牌是第\(i\)张被选中的攻击牌是第\(j\)张

在前\(i\)张强化牌中选择\(k-1\)张,且第\(i\)张必选,所有合法情况下的乘积之和,其实就是\(f_{i,k-1,0}\)。

选择第\(j\)张攻击牌,攻击牌之和其实就是第\(j\)张攻击牌的权值,也就是\(b_j\)。

而若要最终选出的\(k\)张牌是这\(k\)张牌,就剩余\(m-k\)张牌就需要满足:

  • 所有强化牌都必须在第\(i\)张之后。
  • 所有攻击牌都必须在第\(j\)张之后。

因此方案数就是\(C_{2n-i-j}^{m-k}\)。

总结一下,就是枚举\(i,j\),然后每次答案加上\(f_{i,k-1,0}\cdot b_j\cdot C_{2n-i-j}^{m-k}\)。

具体实现可见代码。

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 6000
#define X 998244353
using namespace std;
int n,m,k,a[N+5],b[N+5],C[N+5][N+5],f[N+5][N+5][2],g[N+5][N+5][2];
I bool cmp(CI x,CI y) {return x>y;}
int main()
{
RI i,j;for(C[0][0]=i=1;i<=N;++i) for(C[i][0]=j=1;j<=i;++j) C[i][j]=(C[i-1][j-1]+C[i-1][j])%X;//预处理组合数
RI Tt,ans;scanf("%d",&Tt);W(Tt--)
{
for(scanf("%d%d%d",&n,&m,&k),ans=0,i=1;i<=n;++i) scanf("%d",a+i);
for(i=1;i<=n;++i) scanf("%d",b+i);sort(a+1,a+n+1,cmp),sort(b+1,b+n+1,cmp);//从大到小排序
for(f[0][0][0]=f[0][0][1]=i=1;i<=n;++i) for(f[i][0][1]=j=1;j<=i;++j)//预处理f
f[i][j][0]=1LL*a[i]*f[i-1][j-1][1]%X,f[i][j][1]=(f[i][j][0]+f[i-1][j][1])%X;
for(i=1;i<=n;++i) for(j=1;j<=i;++j)//预处理g
g[i][j][0]=(1LL*b[i]*C[i-1][j-1]+g[i-1][j-1][1])%X,g[i][j][1]=(g[i][j][0]+g[i-1][j][1])%X;
for(i=0;i<k-1;++i) for(j=1;j<=n;++j) ans=(1LL*f[n][i][1]*g[j][k-i][0]%X*C[n-j][m-k]+ans)%X;//当强化牌数量小于k-1时
for(i=0;i<=n;++i) for(j=1;j<=n;++j) ans=(1LL*f[i][k-1][0]*b[j]%X*C[2*n-i-j][m-k]+ans)%X;//当强化拍数量大于等于k-1时
printf("%d\n",ans);//输出答案
}return 0;
}

【洛谷5299】[PKUWC2018] Slay the Spire(组合数学)的更多相关文章

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

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

  2. 洛谷 P5400 - [CTS2019]随机立方体(组合数学+二项式反演)

    洛谷题面传送门 二项式反演好题. 首先看到"恰好 \(k\) 个极大值点",我们可以套路地想到二项式反演,具体来说我们记 \(f_i\) 为钦定 \(i\) 个点为极大值点的方案数 ...

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

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

  4. 洛谷 P6276 - [USACO20OPEN]Exercise P(组合数学+DP)

    洛谷题面传送门 废了,又不会做/ll orz czx 写的什么神仙题解,根本看不懂(%%%%%%%%% 首先显然一个排列的贡献为其所有置换环的乘积.考虑如何算之. 碰到很多数的 LCM 之积只有两种可 ...

  5. 洛谷 P4708 - 画画(Burnside 引理+组合数学)

    洛谷题面传送门 神仙题 %%%%%%%%%%%%%%%%%%%% 题解搬运人来了 首先看到本质不同(无标号)的图计数咱们可以想到 Burnside 引理,具体来说,我们枚举一个排列 \(p\),并统计 ...

  6. [PKUWC2018] Slay the spire

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

  7. 题解-PKUWC2018 Slay the Spire

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

  8. LOJ2538 PKUWC2018 Slay the Spire DP

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

  9. [LOJ2538] [PKUWC2018] Slay the Spire

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

随机推荐

  1. 追踪SQL Server执行delete操作时候不同锁申请与释放的过程

    一直以为很了解sqlserver的加锁过程,在分析一些特殊情况下的死锁之后,尤其是并发单表操作发生的死锁,对于加解锁的过程,有了一些重新的认识,之前的知识还是有一些盲区在里面的.delete加锁与解锁 ...

  2. 官方版vs2008至vs2013下载地址

    Visual Studio 2005 Professional 官方90天试用版 英文版:http://download.microsoft.com/download/e/0/4/e04de840-8 ...

  3. 11. java random类

    一.random类使用 import java.util.Random; public class Demo{ public static void main(){ Random r = new Ra ...

  4. 【使用篇二】SpringBoot集成SpringSecurity(22)

    SpringSecurity是专门针对基于Spring项目的安全框架,充分利用了依赖注入和AOP来实现安全管控.在很多大型企业级系统中权限是最核心的部分,一个系统的好与坏全都在于权限管控是否灵活,是否 ...

  5. [译]Vulkan教程(05)Instance

    [译]Vulkan教程(05)Instance Creating an instance 创建一个instance The very first thing you need to do is ini ...

  6. C语言程序设计100例之(20):过河卒

    例20  过河卒 题目描述 如图1,在棋盘的A点有一个过河卒,需要走到目标B点.卒行走规则:可以向下.或者向右.同时在棋盘上的任一点有一个对方的马(如图1的C点),该马所在的点和所有跳跃一步可达的点称 ...

  7. Maven使用之packaging类型

    项目的打包类型:pom.jar.war 项目中一般使用maven进行模块管理,每个模块下对应都有一个pom文件,pom文件中维护了各模块之间的依赖和继承关系.项目模块化可以将通用的部分抽离出来,方便重 ...

  8. css样式优先级计算规则

    css样式的优先级分为引入优先级和声明优先级. 引入优先级 引入样式一般分为外部样式,内部样式,内联样式. 外部样式:使用link引入的外部css文件. 内部样式:使用style标签书写的css样式. ...

  9. ASP.NET Core SignalR:基础概述

    一.简介 ASP.NET Core SignalR 是一个开源代码库,它简化了向应用添加实时 Web 功能的过程. 实时 Web 功能使服务器端代码能够即时将内容推送到客户端. SignalR 的适用 ...

  10. Slickflow.NET 开源工作流引擎高级开发(五) -- 引擎和外部事件的交互

    前言:引擎组件的基本职责是负责流程流转,但是在流转过程中,除了对内部控制逻辑进行实现外,也不可避免的要去调用或者响应外部事件.本文主要描述外部事件的类型,以及调用方法过程. 1. 外部事件的类型 外部 ...