【题解】LOJ #2325 「清华集训 2017」小 Y 和恐怖的奴隶主(矩阵快速幂)
【题解】LOJ #2325 「清华集训 2017」小 Y 和恐怖的奴隶主(矩阵快速幂)
设\(f(i,a,b,c)\)表示进行到\(i\)次攻击,血量分别为\(1,2,3\)的怪的数量为\(a,b,c\)的概率。如果你设表示攻击boss的次数期望的话就还要而外记录一个概率,不然无法转移,所以不如直接设成概率,每次转移\(f(i,a,b,c)\to f(i+1,a,b,c)\)的时候叠加一下答案即可(贡献为\(f(i,a,b,c)\over a+b+c+1\)),可以看做是\(ans(i)=ans(i-1)+\sum {f(i,a,b,c)\over a+b+c+1}\),和\(f\)一起dp即可。
状态数乍一看是\(8^3\),但是考虑到\(a+b+c\le 8\),也就是方程\(x_1+x_2+x_3+x_4=8\)的解的个数,解的数量是\({4+8-1\choose 8}=165\)。
那么考虑矩阵快速幂就好了,注意到询问次数比较多,用向量优化的方法就行了。
//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std; typedef long long ll;
inline ll qr(){
ll ret=0,f=0,c=getchar();
while(!isdigit(c)) f|=c==45,c=getchar();
while( isdigit(c)) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
const int mod=998244353;
int MOD(const int&x){return x>=mod?x-mod:x;}
int MOD(const int&x,const int&y){return 1ll*x*y%mod;}
int st[10][10][10],vec[maxn],temp[maxn],id;
// 1(a)2(b)3(c)
const int maxn=166;
struct{int x,y,z;}rem[maxn];
struct MAT{
int v[maxn][maxn];
MAT(){memset(v,0,sizeof(int)*maxn*maxn);}
int* operator [](const int&x){return v[x];};
MAT operator * (const MAT&x)const{
MAT ret;
for(int k=0;k<=id;++k)
for(int t=0;t<=id;++t)
for(int i=0;i<=id;++i)
ret[t][i]=MOD(ret[t][i]+MOD(v[t][k],x.v[k][i]));
return ret;
}
}mi[61];
int ksm(const int&ba,const int&p){
int ret=1;
for(int t=p,b=ba;t;t>>=1,b=MOD(b,b))
if(t&1) ret=MOD(ret,b);
return ret;
}
int main(){
int T=qr(),m=qr(),k=qr();
for(int a=0;a<=k;++a)
for(int b=0;(b+a<=k&&m>=2)||b==0;++b)
for(int c=0;(a+b+c<=k&&m>=3)||c==0;++c)
rem[id]={a,b,c},st[a][b][c]=id++;
for(int t=0;t<id;++t){
int a=rem[t].x,b=rem[t].y,c=rem[t].z,inv=ksm(a+b+c+1,mod-2);
//hit boss
mi[0][t][t]=inv;
mi[0][t][id]=inv;
//hit a (1 hp)
if(a) mi[0][t][st[a-1][b][c]]=MOD(a,inv);
//hit b (2 hp)
if(b) mi[0][t][st[a+1][b-1+(a+b<k&&m==2)][c+(a+b+c<k&&m==3)]]=MOD(b,inv);
//hit c (3 hp)
if(c) mi[0][t][st[a][b+1][c-1+(a+b+c<k)]]=MOD(c,inv);
}
mi[0][id][id]=1;
for(int t=1;t<=60;++t) mi[t]=mi[t-1]*mi[t-1];
while(T--){
memset(vec,0,sizeof vec);
ll n=qr();
vec[st[m==1][m==2][m==3]]=1;
for(int t=0;t<=60;++t,n>>=1)
if(n&1){
memcpy(temp,vec,sizeof vec);
memset(vec,0,sizeof vec);
for(int j=0;j<=id;++j)
for(int i=0;i<=id;++i)
vec[i]=MOD(vec[i]+MOD(mi[t][j][i],temp[j]));
}
printf("%d\n",vec[id]);
}
return 0;
}
博客保留所有权利,谢绝学步园、码迷等不在文首明显处显著标明转载来源的任何个人或组织进行转载!其他文明转载授权且欢迎!