P4007 小 Y 和恐怖的奴隶主

题目链接:Luogu P4007 UOJ #340 LOJ #2325

“A fight? Count me in!” 要打架了,算我一个。

“Everyone, get in here!” 所有人,都过来!

小 Y 是一个喜欢玩游戏的 OIer。一天,她正在玩一款游戏,要打一个 Boss。

虽然这个 Boss 有 $10^{100}$ 点生命值,但它只带了一个随从——一个只有 $m$ 点生命值的“恐怖的奴隶主”。

这个“恐怖的奴隶主”有一个特殊的技能:每当它被扣减生命值但没有死亡(死亡即生命值 $\leq 0$),且 Boss 的随从数量小于上限 $k$,便会召唤一个新的具有 $m$ 点生命值的“恐怖的奴隶主”。

现在小 Y 可以进行 $n$ 次攻击,每次攻击时,会从 Boss 以及 Boss 的所有随从中的等概率随机选择一个,并扣减 $1$ 点生命值,她想知道进行 $n$ 次攻击后扣减 Boss 的生命值点数的期望。为了避免精度误差,你的答案需要对 $998244353$ 取模。

在所有测试点中,$1 \leq T \leq 1000, 1 \leq n \leq {10}^{18}, 1 \leq m \leq 3, 1 \leq k \leq 8$。

Tutorial

记 $f_{i,a,b,c}$ 为当前第 $i$ 轮,有 $a$ 个一血,$b$ 个二血,$c$ 个三血的概率。转移讨论即可。

再设 $g_i$ 表示前 $i$ 轮对 Boss 的期望攻击,可从 $f_{i,a,b,c}$ 由 $\frac 1{a+b+c+1}$ 的概率转移而来。

通过计算可得,$k\leq 8$ 故实际可用状态仅有 $166$ 个(算上 $g_i$)。

直接矩阵快速幂复杂度是 $O(T166^3\log N)$。

设转移矩阵为 $M$,可与先处理出 $M^{2^k}$,询问可直接用行向量乘上 $\log N$ 个矩阵即可,时间复杂度为 $O(166^3\log N+T166^2\log N)$。

另外还有一种 Berlekamp-Massey 优化矩阵快速幂的方法。

Solution

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define W while
#define I inline
#define RI register int
#define LL long long
#define Cn const
#define CI Cn int&
#define gc getchar
#define D isdigit(c=gc())
#define pc(c) putchar((c))
#define min(x,y) ((x)<(y)?(x):(y))
#define max(x,y) ((x)>(y)?(x):(y))
using namespace std;
namespace Debug{
Tp I void _debug(Cn char* f,Ty t){cerr<<f<<'='<<t<<endl;}
Ts I void _debug(Cn char* f,Ty x,Ar... y){W(*f!=',') cerr<<*f++;cerr<<'='<<x<<",";_debug(f+1,y...);}
Tp ostream& operator<<(ostream& os,Cn vector<Ty>& V){os<<"[";for(Cn auto& vv:V) os<<vv<<",";os<<"]";return os;}
#define gdb(...) _debug(#__VA_ARGS__,__VA_ARGS__)
}using namespace Debug;
namespace FastIO{
Tp I void read(Ty& x){char c;int f=1;x=0;W(!D) f=c^'-'?1:-1;W(x=(x<<3)+(x<<1)+(c&15),D);x*=f;}
Ts I void read(Ty& x,Ar&... y){read(x),read(y...);}
Tp I void write(Ty x){x<0&&(pc('-'),x=-x,0),x<10?(pc(x+'0'),0):(write(x/10),pc(x%10+'0'),0);}
Tp I void writeln(Cn Ty& x){write(x),pc('\n');}
}using namespace FastIO;
Cn int N=168,p=998244353;
I int QP(RI a,RI b){RI s=1;W(b) b&1&&(s=1LL*s*a%p),a=1LL*a*a%p,b>>=1;return s;}
int T,m,k,cnt,id[9][9][9],inv[11];
struct Matrix{int a[N][N];I void clear(){memset(a,0,sizeof(a));}}F[70];
I Matrix Mul(Cn Matrix& A,Cn Matrix& B){Matrix C;C.clear();RI i,j,k;for(i=1;i<=cnt;i++) for(j=1;j<=cnt;j++){__int128 t=0;for(k=1;k<=cnt;k++) t+=1LL*A.a[i][k]*B.a[k][j];C.a[i][j]=t%p;}return C;}
struct Vector{int a[N];I void clear(){memset(a,0,sizeof(a));}}v;
I Vector Mul(Cn Vector& A,Cn Matrix& B){Vector C;C.clear();RI i,j;for(i=1;i<=cnt;i++){__int128 t=0;for(j=1;j<=cnt;j++) t+=1LL*A.a[j]*B.a[j][i];C.a[i]=t%p;}return C;}
int main(){
RI i,j,a,b,c;LL x;read(T,m,k);for(a=0;a<=k;a++) for(b=0;b<=(m>=2?k-a:0);b++) for(c=0;c<=(m>=3?k-a-b:0);c++) id[a][b][c]=++cnt;
for(i=1;i<=9;i++) inv[i]=QP(i,p-2);
++cnt,F[0].a[cnt][cnt]=1;for(a=0;a<=k;a++) for(b=0;b<=(m>=2?k-a:0);b++) for(c=0;c<=(m>=3?k-a-b:0);c++){
RI i=id[a][b][c],div=inv[a+b+c+1],add=(a+b+c<k);
a&&(F[0].a[i][id[a-1][b][c]]=1LL*a*div%p);
if(m==2) b&&(F[0].a[i][id[a+1][b-1+add][c]]=1LL*b*div%p);
if(m==3) b&&(F[0].a[i][id[a+1][b-1][c+add]]=1LL*b*div%p),c&&(F[0].a[i][id[a][b+1][c-1+add]]=1LL*c*div%p);
F[0].a[i][i]=F[0].a[i][cnt]=div;
}for(i=1;i<=62;i++) F[i]=Mul(F[i-1],F[i-1]);for(i=1;i<=T;i++){
read(x),v.clear(),v.a[id[m==1][m==2][m==3]]=1;
for(j=0;j<=62;j++) x>>j&1&&(v=Mul(v,F[j]),0);
writeln(v.a[cnt]);
}return 0;
}