题目链接: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。
记 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 优化矩阵快速幂的方法。
#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;
}