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( ...
随机推荐
- R画韦恩图之总结
本文分享自微信公众号 - 生信科技爱好者(bioitee).如有侵权,请联系 support@oschina.cn 删除.本文参与"OSC源创计划",欢迎正在阅读的你也加入,一起分 ...
- Vue——登录小案例、scoped、ref属性、props其他、混入mixin、插件、Element-ui
解析Vue项目 # 1 为什么浏览器中访问某个地址,会显示某个页面组件 根组件:APP.vue 必须是 <template> <div id="app"> ...
- 拥抱jsx,开启vue3用法的另一种选择🔥🔥
背景 公司高级表单组件ProForm高阶组件都建立在jsx的运用配置上,项目在实践落地过程中积累了丰富的经验,也充分感受到了jsx语法的灵活便捷和可维护性强大,享受到了用其开发的乐趣,独乐乐不如众乐乐 ...
- linux awk文本
目录 一.awk概念 二.awk的工作过程 三.awk字符 四.内置变量 五.getline 六.awk的精准筛选 七.例子演示 八.实验演示 一.awk概念 1.概念:awk 是一个功能强大的编辑 ...
- 尚医通day11-Java中阿里云对象存储OSS
页面预览 用户认证 用户登录成功后都要进行身份认证,认证通过后才可以预约挂号. 认证过程:用户填写基本信息(姓名.证件类型.证件号码和证件照片),提交平台审核 用户认证相关接口: (1)上传证件图片 ...
- RabbitMQ快速使用代码手册
本篇博客的内容为RabbitMQ在开发过程中的快速上手使用,侧重于代码部分,几乎没有相关概念的介绍,相关概念请参考以下csdn博客,两篇都是我找的精华帖,供大家学习.本篇博客也持续更新~~~ 内容代码 ...
- 整理spring-web里支持的文件以及对应的Content-Type
前言 最近在弄文件上传.下载.在线预览时经常需要设置请求标头或者响应标头的Content-Type 属性.所以研究了一下spring支持哪些Content-Type,通过研究MediaTypeFact ...
- 如何优化数据warehouse的搜索和查询
目录 1. 引言 2. 技术原理及概念 2.1 基本概念解释 2.2 技术原理介绍 2.2.1 查询优化 2.2.2 索引优化 2.2.3 数据访问优化 2.3 相关技术比较 2.3.1 SQL 2. ...
- 从2PC和容错共识算法讨论zookeeper中的Create请求
最近在读<数据密集型应用系统设计>,其中谈到了zookeeper对容错共识算法的应用.这让我想到之前参考的zookeeper学习资料中,误将容错共识算法写成了2PC(两阶段提交协议),所以 ...
- .Net 472&6.0 Razor编译时的小差异
前言 几个月前在进行着.Net 472到6.0的升级,复用原有代码,在对Razor进行迁移中,发现原运行正常的代码,却存在报错,深入研究发现是Core下对Razor编译有一些变动. 问题复现 472 ...