Description

Link.

这道题 的加强版。

Solution

题解里面大多数都是概率 DP,或者是期望 DP 然后是逆推。甚至不给 DP 的转移式。机房 yyds Reanap 发了一篇逆推的题解,那我就来补一篇正推的期望 DP 的填表法做法。

首先这道题看上去好像可以状压的样子,我们可以设 \(f_{i,S}\) 表示当前打了 \(i\) 次,敌方的情况是 \(S\) 的期望。

不过仔细想一下发现我们只需要知道各种血量的奴隶主有多少即可。

于是我们重新设计 DP 的状态:\(f_{s,i,j,k}\) 表示目前打了 \(s\) 次,敌方分别有 \(i\)、\(j\)、\(k\) 个 1hp、2hp、3hp 的奴隶主。

首先我们令 \(T=[i+j+k<K]\)

那么我们的方程就是:

\[f_{s,i,j,k}=\begin{cases}
f_{s-1,i-1,j,k}+\frac{i}{i+j+k+1},M=1\land i\neq0 \\
f_{s-1,i-1,j,k}+\frac{i}{i+j+k+1},M=2\land i\neq0 \\
f_{s-1,i+1,j-1+T,k}+\frac{j}{i+j+k+1},M=2\land j\neq0 \\
f_{s-1,i-1,j,k}+\frac{i}{i+j+k+1},M=3\land i\neq0 \\
f_{s-1,i+1,j-1,k+T}+\frac{j}{i+j+k+1},M=3\land j\neq0 \\
f_{s-1,i,j+1,k-1+T}+\frac{k}{i+j+k+1},M=3\land k\neq0
\end{cases}
\]

这个方程挺好理解的,基本就等于照题意模拟。

然后我们发现转移式中的系数部分和 \(f\) 数组没有关系,所以我们可以用矩阵来加速这个东西。

数一数状态数,直接加速直接 T 飞。

有一个矩阵加速常用的 trick,预处理矩阵 2 的幂。

然后取模卡卡常即可。

(代码不保证稳定能过)

#include <cstdio>
#define mod ( 998244353 ) using namespace std;
typedef long long LL; char buf[1 << 21], *p1 = buf, *p2 = buf;
#define getchar( ) ( p1 == p2 && ( p2 = ( p1 = buf ) + fread( buf, 1, 1 << 21, stdin ), p1 == p2 ) ? EOF : *p1 ++ ) template<typename _T>
void read( _T &x )
{
x = 0;
char c = getchar( );
_T f = 1;
while( c < '0' || c > '9' )
{
if( c == '-' ) f = -1;
c = getchar( );
}
while( c >= '0' && c <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ( c ^ '0' ), c = getchar( );
x *= f;
} template<typename _T, typename... Args>
void read( _T &t, Args&... args ) { read( t ), read( args... ); } template<typename _T>
void write( _T x )
{
if( x < 0 ) putchar( '-' ), x = -x;
if( x > 9 ) write( x / 10 );
putchar( x % 10 + '0' );
} template<typename _T>
void Add( _T &x, _T y )
{
if( y >= mod ) y %= mod;
x += y;
if( x >= mod ) x -= mod;
} template<typename _T>
_T square( _T x ) { return x * x; } const int Maxn = 10 + 5, Maxk = 170 + 5;
int T, M, K, S, Unite[Maxn][Maxn][Maxn];
LL tmp[Maxk], Ans[Maxk], Inv[Maxn];
struct Matrix
{
LL mat[Maxk][Maxk]; friend Matrix operator * ( const Matrix &one, const Matrix &another )
{
Matrix res;
for( int i = 0; i <= S + 1; ++ i )
{
for( int j = 0; j <= S + 1; ++ j )
{
res.mat[i][j] = 0;
for( int k = 0; k <= S + 1; ++ k ) Add( res.mat[i][j], one.mat[i][k] * another.mat[k][j] );
}
}
return res;
}
} dp[Maxk]; template<typename _T>
_T qkpow( _T base, _T times )
{
_T res = 1;
while( times )
{
if( times & 1 ) res = ( LL )res * base % mod;
base = ( LL )base * base % mod;
times >>= 1;
}
return res;
} void progressInversions( ) { for( int i = 0; i <= 10; ++ i ) Inv[i] = qkpow( i, mod - 2 ); }
signed main( )
{
progressInversions( );
read( T, M, K );
for( int i = 0; i <= K; ++ i )
{
int UpI;
if( M > 1 ) UpI = K - i;
else UpI = 0;
for( int j = 0; j <= UpI; ++ j )
{
int UpJ;
if( M > 2 ) UpJ = K - i - j;
else UpJ = 0;
for( int k = 0; k <= UpJ; ++ k ) Unite[i][j][k] = ++ S;
}
}
for( int i = 0; i <= K; ++ i )
{
int UpI;
if( M > 1 ) UpI = K - i;
else UpI = 0;
for( int j = 0; j <= UpI; ++ j )
{
int UpJ;
if( M > 2 ) UpJ = K - i - j;
else UpJ = 0;
for( int k = 0; k <= UpJ; ++ k )
{
int Add;
if( i + j + k < K ) Add = 1;
else Add = 0;
if( M == 1 && i ) dp[0].mat[Unite[i][j][k]][Unite[i - 1][j][k]] = ( LL )i * Inv[i + j + k + 1] % mod;
else if( M == 2 )
{
if( i ) dp[0].mat[Unite[i][j][k]][Unite[i - 1][j][k]] = ( LL )i * Inv[i + j + k + 1] % mod;
if( j ) dp[0].mat[Unite[i][j][k]][Unite[i + 1][j - 1 + Add][k]] = ( LL )j * Inv[i + j + k + 1] % mod;
}
else if( M == 3 )
{
if( i ) dp[0].mat[Unite[i][j][k]][Unite[i - 1][j][k]] = ( LL )i * Inv[i + j + k + 1] % mod;
if( j ) dp[0].mat[Unite[i][j][k]][Unite[i + 1][j - 1][k + Add]] = ( LL )j * Inv[i + j + k + 1] % mod;
if( k ) dp[0].mat[Unite[i][j][k]][Unite[i][j + 1][k - 1 + Add]] = ( LL )k * Inv[i + j + k + 1] % mod;
}
dp[0].mat[Unite[i][j][k]][Unite[i][j][k]] = dp[0].mat[Unite[i][j][k]][S + 1] = Inv[i + j + k + 1];
}
}
}
dp[0].mat[S + 1][S + 1] = 1;
for( int i = 1; i <= 60; ++ i ) dp[i] = square( dp[i - 1] );
while( T -- > 0 )
{
LL N;
read( N );
for( int i = 0; i <= S + 1; ++ i ) Ans[i] = 0;
if( M == 1 ) Ans[Unite[1][0][0]] = 1;
else if( M == 2 ) Ans[Unite[0][1][0]] = 1;
else Ans[Unite[0][0][1]] = 1;
for( int i = 0; i <= 60; ++ i )
{
if( ( N >> i ) & 1 )
{
for( int j = 0; j <= S + 1; ++ j )
{
tmp[j] = 0;
for( int k = 0; k <= S + 1; ++ k ) Add( tmp[j], Ans[k] * dp[i].mat[k][j] );
}
for( int j = 0; j <= S + 1; ++ j ) Ans[j] = tmp[j];
}
}
write( Ans[S + 1] ), putchar( '\n' );
}
return 0;
}

Solution -「洛谷 P4007」小 Y 和恐怖的奴隶主的更多相关文章

  1. loj #2325. 「清华集训 2017」小Y和恐怖的奴隶主

    #2325. 「清华集训 2017」小Y和恐怖的奴隶主 内存限制:256 MiB时间限制:2000 ms标准输入输出 题目类型:传统评测方式:文本比较   题目描述 "A fight? Co ...

  2. 【loj2325】「清华集训 2017」小Y和恐怖的奴隶主 概率dp+倍增+矩阵乘法

    题目描述 你有一个m点生命值的奴隶主,奴隶主受伤未死且当前随从数目不超过k则再召唤一个m点生命值的奴隶主. T次询问,每次询问如果如果对面下出一个n点攻击力的克苏恩,你的英雄期望会受到到多少伤害. 输 ...

  3. LibreOJ #2325. 「清华集训 2017」小Y和恐怖的奴隶主(矩阵快速幂优化DP)

    哇这题剧毒,卡了好久常数才过T_T 设$f(i,s)$为到第$i$轮攻击,怪物状态为$s$时对boss的期望伤害,$sum$为状态$s$所表示的怪物个数,得到朴素的DP方程$f(i,s)=\sum \ ...

  4. LOJ2325. 「清华集训 2017」小 Y 和恐怖的奴隶主【矩阵快速幂优化DP】【倍增优化】

    LINK 思路 首先是考虑怎么设计dp的状态 发现奴隶主的顺序没有影响,只有生命和个数有影响,所以就可以把每个生命值的奴隶主有多少压缩成状态就可以了 然后发现无论是什么时候一个状态到另一个状态的转移都 ...

  5. LOJ2325「清华集训 2017」小Y和恐怖的奴隶主

    题目链接 首先dp很显然,\(f(i,s)\)表示到了第i轮,各种血量人数的情况为s今后的期望攻击boss次数.那么有\(f(i,s)=\frac{1}{num+1}*\sum_{s->s'}( ...

  6. Solution -「洛谷 P4372」Out of Sorts P

    \(\mathcal{Description}\)   OurOJ & 洛谷 P4372(几乎一致)   设计一个排序算法,设现在对 \(\{a_n\}\) 中 \([l,r]\) 内的元素排 ...

  7. Note/Solution -「洛谷 P5158」「模板」多项式快速插值

    \(\mathcal{Description}\)   Link.   给定 \(n\) 个点 \((x_i,y_i)\),求一个不超过 \(n-1\) 次的多项式 \(f(x)\),使得 \(f(x ...

  8. Solution -「洛谷 P4719」「模板」"动态 DP" & 动态树分治

    \(\mathcal{Description}\)   Link.   给定一棵 \(n\) 个结点的带权树,\(m\) 次单点点权修改,求出每次修改后的带权最大独立集.   \(n,m\le10^5 ...

  9. Solution -「洛谷 P4198」楼房重建

    \(\mathcal{Description}\)   Link.   给定点集 \(\{P_n\}\),\(P_i=(i,h_i)\),\(m\) 次修改,每次修改某个 \(h_i\),在每次修改后 ...

  10. Solution -「洛谷 P6577」「模板」二分图最大权完美匹配

    \(\mathcal{Description}\)   Link.   给定二分图 \(G=(V=X\cup Y,E)\),\(|X|=|Y|=n\),边 \((u,v)\in E\) 有权 \(w( ...

随机推荐

  1. 2023-06-03:redis中pipeline有什么好处,为什么要用 pipeline?

    2023-06-03:redis中pipeline有什么好处,为什么要用 pipeline? 答案2023-06-03: Redis客户端执行一条命令通常包括以下四个阶段: 1.发送命令:客户端将要执 ...

  2. 浙大Jarvisoj [XMAN]level6 Writeup

    分析代码 初始化 0x0804A2EC:保存malloc(0xC10)返回的指针 malloc(0xC10) 0 1 ... ... value note 总数:256 已使用 note 数 0 一. ...

  3. element-ui Tabs 标签页刷新页面状态不丢失

    element-ui Tabs 标签页刷新页面状态不丢失 转载请表明出处 https://www.cnblogs.com/niexianda/p/14765111.html 效果 一般在使用Tabs组 ...

  4. 前端Vue自定义询问弹框和输入弹框

    前端Vue自定义询问弹框和输入弹框, 下载完整代码请访问uni-app插件市场地址:https://ext.dcloud.net.cn/plugin?id=13119 效果图如下: 使用方法 < ...

  5. 前端vue自定义简单实用下拉筛选 下拉菜单

    前端vue自定义简单实用下拉筛选 下拉菜单, 下载完整代码请访问: https://ext.dcloud.net.cn/plugin?id=13020 效果图如下:     #### 使用方法 ``` ...

  6. K8S | 容器和Pod组件

    对比软件安装和运行: 一.场景 作为研发人员,通常自己电脑的系统环境都是非常复杂,在个人的习惯上,是按照下图的模块管理电脑的系统环境: 对于「基础设施」.「主机操作系统」.「系统软件」来说,通常只做配 ...

  7. python学习--采集弹幕信息

    # -*- coding: utf-8 -*-"""Created on Mon Nov 4 12:00:12 2019 @author: DELL"" ...

  8. 基于ClickHouse解决活动海量数据问题

    1.背景 魔笛活动平台要记录每个活动的用户行为数据,帮助客服.运营.产品.研发等快速处理客诉.解决线上问题并进行相关数据分析和报警.可以预见到需要存储和分析海量数据,预估至少几十亿甚至上百亿的数据量, ...

  9. SAS - PROC FCMP

    PROC FCMP 概述 PROC FCMP 可用于自定义函数(funcion)和子程序(subroutines).自定义函数和子程序的名称的最大长度为 32,长度超过 32 的名称虽然可以定义,但无 ...

  10. Django基本数据库操作

    Django基本数据库操作 @ 目录 Django基本数据库操作 ‍内容一:基本数据库配置 ‍内容二:ORM基本操作 ‍内容一:基本数据库配置 Django是一个流行的Python Web框架,它可以 ...