Luogu P4007 小 Y 和恐怖的奴隶主
Link
设\(f_{i,a,b,c}\)为第\(i\)次攻击时,场上还有\(a,b,c\)个\(1,2,3\)血的随从的概率。
转移随便讨论一下就行了。
设\(g_i\)表示前\(i\)次攻击对 Boss 造成的期望伤害,转移就是\(\frac1{a+b+c+1}f_{i,a,b,c}\rightarrow g_i\)。
因为\(k\le8\),所以实际上状态很少,总共只有\(z=166\)个。
倍增预处理转移矩阵的\(2^k\)次幂,查询时拿行向量乘上对应的转移矩阵即可,时间复杂度为\(O(z^3\log n+Tz^2\log n)\)。
#include<cstdio>
#include<cstring>
using i64=long long;
const int N=170;const i64 P=998244353,inv[]={1,1,499122177,332748118,748683265,598946612,166374059,855638017,873463809,443664157};
int tot=1,st[N],id[1<<12];
struct matrix{i64 a[N][N];matrix(){memset(a,0,sizeof a);}i64*operator[](int x){return a[x];}}E[60];
void operator*(matrix&a,matrix&b){for(int i=0;i<tot;++i)for(int j=0;j<tot;++j){__int128 c=0;for(int k=0;k<tot;++k)c+=b[i][k]*b[k][j];a[i][j]=c%P;}}
struct vector{i64 a[N];vector(){memset(a,0,sizeof a);}i64&operator[](int x){return a[x];}};
void operator*(vector&a,matrix&b){vector c;for(int i=0;i<tot;++i){__int128 d=0;for(int j=0;j<tot;++j)d+=a[j]*b[j][i];c[i]=d%P;}a=c;}
i64 read(){i64 x;scanf("%lld",&x);return x;}
void dfs(int i,int k,int s)
{
if(i--){s<<=4;for(int a=0;a<=k;++a)dfs(i,k-a,s|a);}
else st[id[s]=tot++]=s;
}
int main()
{
int T=read(),m=read(),k=read();
dfs(m,k,0),E[0][0][0]=1;
for(int i=1;i<tot;++i)
{
int s=st[i],u=(1+s+(s>>4)+(s>>8))&15;
E[0][i][i]=E[0][i][0]=inv[u];
for(int j=0;j<m;++j)
if(int l=s>>(j<<2)&15)
{
int t=s-(1<<(j<<2));
if(j+1<m) t+=(1<<((j+1)<<2))+(u<=k);
if(id[t]) (E[0][i][id[t]]+=l*inv[u])%=P;
}
}
for(int i=1;i<60;++i) E[i]*E[i-1];
while(T--)
{
i64 n=read();vector I;I[2]=1;
for(int i=0;i<60;++i) if(n>>i&1) I*E[i];
printf("%lld\n",I[0]);
}
}