Solution -「洛谷 P4007」小 Y 和恐怖的奴隶主
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-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 和恐怖的奴隶主的更多相关文章
- loj #2325. 「清华集训 2017」小Y和恐怖的奴隶主
#2325. 「清华集训 2017」小Y和恐怖的奴隶主 内存限制:256 MiB时间限制:2000 ms标准输入输出 题目类型:传统评测方式:文本比较 题目描述 "A fight? Co ...
- 【loj2325】「清华集训 2017」小Y和恐怖的奴隶主 概率dp+倍增+矩阵乘法
题目描述 你有一个m点生命值的奴隶主,奴隶主受伤未死且当前随从数目不超过k则再召唤一个m点生命值的奴隶主. T次询问,每次询问如果如果对面下出一个n点攻击力的克苏恩,你的英雄期望会受到到多少伤害. 输 ...
- LibreOJ #2325. 「清华集训 2017」小Y和恐怖的奴隶主(矩阵快速幂优化DP)
哇这题剧毒,卡了好久常数才过T_T 设$f(i,s)$为到第$i$轮攻击,怪物状态为$s$时对boss的期望伤害,$sum$为状态$s$所表示的怪物个数,得到朴素的DP方程$f(i,s)=\sum \ ...
- LOJ2325. 「清华集训 2017」小 Y 和恐怖的奴隶主【矩阵快速幂优化DP】【倍增优化】
LINK 思路 首先是考虑怎么设计dp的状态 发现奴隶主的顺序没有影响,只有生命和个数有影响,所以就可以把每个生命值的奴隶主有多少压缩成状态就可以了 然后发现无论是什么时候一个状态到另一个状态的转移都 ...
- LOJ2325「清华集训 2017」小Y和恐怖的奴隶主
题目链接 首先dp很显然,\(f(i,s)\)表示到了第i轮,各种血量人数的情况为s今后的期望攻击boss次数.那么有\(f(i,s)=\frac{1}{num+1}*\sum_{s->s'}( ...
- Solution -「洛谷 P4372」Out of Sorts P
\(\mathcal{Description}\) OurOJ & 洛谷 P4372(几乎一致) 设计一个排序算法,设现在对 \(\{a_n\}\) 中 \([l,r]\) 内的元素排 ...
- Note/Solution -「洛谷 P5158」「模板」多项式快速插值
\(\mathcal{Description}\) Link. 给定 \(n\) 个点 \((x_i,y_i)\),求一个不超过 \(n-1\) 次的多项式 \(f(x)\),使得 \(f(x ...
- Solution -「洛谷 P4719」「模板」"动态 DP" & 动态树分治
\(\mathcal{Description}\) Link. 给定一棵 \(n\) 个结点的带权树,\(m\) 次单点点权修改,求出每次修改后的带权最大独立集. \(n,m\le10^5 ...
- Solution -「洛谷 P4198」楼房重建
\(\mathcal{Description}\) Link. 给定点集 \(\{P_n\}\),\(P_i=(i,h_i)\),\(m\) 次修改,每次修改某个 \(h_i\),在每次修改后 ...
- Solution -「洛谷 P6577」「模板」二分图最大权完美匹配
\(\mathcal{Description}\) Link. 给定二分图 \(G=(V=X\cup Y,E)\),\(|X|=|Y|=n\),边 \((u,v)\in E\) 有权 \(w( ...
随机推荐
- Java 网络编程 —— 客户端协议处理框架
概述 Java 对客户程序的通信过程进行了抽象,提供了通用的协议处理框架,该框架封装了 Socket,主要包括以下类: URL 类:统一资源定位符,表示客户程序要访问的远程资源 URLConnecti ...
- 隐藏Tomcat中间件名称及版本号
目的 防止黑客利用Tomcat中间件及版本号有针对性发起攻击. 处理方法 输入命令方式 # 进入tomcat/lib目录 cd Tomcat目录/lib # 解决catalina.jar,备份Serv ...
- CANoe _ Panel面板的创建过程
在Canoe中创建Panel面板,用于显示和操作CAN网络的数据和信号,遵循以下步骤: 1.打开Canoe 启动Canoe软件. 2.打开项目 在Canoe的菜单栏中,选择"File&quo ...
- 【保姆级教学】抓包工具Wireshark使用教程
wireshark介绍 今天讲一下另一款底层抓包软件,之前写过两篇抓包软件 分别是 fiddler抓包[https://www.cnblogs.com/zichliang/p/16067941.htm ...
- CKS 考试题整理 (04)-secret
Task 在 namespace istio-system 中获取名为 db1-test 的现有secret的内容 将 username 字段存储在名为 /cks/sec/user.txt 的文件中, ...
- C# - XMLHelper :一个操作XML的简单类库
下午写了一个操作XML文件的类库,后来不用了,水篇文章存个档 整体功能 XMLHelper.cs主要提供以下功能: 加载XML文件:从文件路径或字符串中加载XML文档,并返回XmlDocument对象 ...
- AI-4多层感知机
4.1笔记 在线性网络中,任何特征的增大都会导致模型输出的增大或减小.这种想法在某些情况下不在适用,例如x和y并非线性关系.或者是x和y并不具有单调性.以及x1.x2会对y产生交互作用时. 为解决该问 ...
- python接口自动化封装导出excel方法和读写excel数据
一.首先需要思考,我们在页面导出excel,用python导出如何写入文件的 封装前需要确认python导出excel接口返回的是一个什么样的数据类型 如下:我们先看下不对返回结果做处理,直接接收数据 ...
- C#中数组=out参数?
- 结论 先上结论,答案是yes,C#中数组确实具有out参数的特性. - 疑问 最近开发一个上位机的功能,有段代码看得我一直很迷糊,我的认识,函数的执行结果,要么在函数中通过return返回,要么通 ...
- 02LED灯
目录 一.LED灯是什么 二.原理图 三.对LED进行操作 1.点亮第一个LED灯 2.LED双数点亮 3.LED流水灯 四.延迟函数的生成 一.LED灯是什么 LED是一个发光二极管,当一段为高电平 ...