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} ightarrow g_i)
因为(kle8),所以实际上状态很少,总共只有(z=166)个。
倍增预处理转移矩阵的(2^k)次幂,查询时拿行向量乘上对应的转移矩阵即可,时间复杂度为(O(z^3log n+Tz^2log 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
",I[0]);
    }
}
原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/13035737.html