LOJ传送门
洛谷传送门
解析:
显然 m m m这么小不是拿来看看完事的。
我们发现真正影响当前状态的只有每种血量的小怪的个数。
打表 m = 3 , K = 8 m=3,K=8 m=3,K=8发现合法的情况只有165种。
所以我们只需要给每个状态一个编号就可以把矩阵压到 165 165 165了
每种状态 i , j , k i,j,k i,j,k(三种血量的分别有 i , j , k i,j,k i,j,k个)对答案的贡献是 P ( i , j , k ) / ( i + j + k + 1 ) P(i,j,k)/(i+j+k+1) P(i,j,k)/(i+j+k+1), P P P表示达到这个状态的概率。
矩阵再开最后一行记录期望前缀和(即答案)。
暴力预处理所有状态到其他状态的转移系数矩阵,以及2的若干次幂的矩阵。
然后每个询问就可以 O ( 16 6 2 log n ) O(166^2\log n) O(1662logn)回答了。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<20|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline ll getint(){
re char c;
while(!isdigit(c=gc()));re ll num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
}
using namespace IO;
using std::cout;
using std::cerr;
cs int mod=998244353;
inline int add(int a,int b){return (a+b>=mod)?a+b-mod:a+b;}
inline void Inc(int &a,int b){(a+=b)>=mod?a-=mod:a;}
inline int dec(int a,int b){return a<b?a-b+mod:a-b;}
inline int mul(int a,int b){return (ll)a*b%mod;}
inline int quickpow(int a,int b,int res=1){
while(b){
if(b&1)res=mul(res,a);
a=mul(a,a);
b>>=1;
}
return res;
}
int T,m,K;
int id1[9],id2[9][9],id3[9][9][9];
int SIZE;
inline void dfs(int cur,int tmp){
static int rec[4];
if(cur>m)switch(m){
case 1:id1[rec[1]]=SIZE++;return ;
case 2:id2[rec[1]][rec[2]]=SIZE++;return ;
case 3:id3[rec[1]][rec[2]][rec[3]]=SIZE++;return ;
}
for(int re i=0;i<=tmp;++i)rec[cur]=i,dfs(cur+1,tmp-i);
}
struct matrix{
static cs int Mat=167;
int a[Mat][Mat],r,c;
matrix(){}
matrix(int _r,int _c):r(_r),c(_c){memset(a,0,sizeof a);}
int *operator[](int offset){return a[offset];}
cs int *operator[](int offset)cs{return a[offset];}
friend matrix operator*(cs matrix &A,cs matrix &B){
matrix C(A.r,B.c);
for(int re i=0;i<A.r;++i)
for(int re j=0;j<B.r;++j)if(A[i][j])
for(int re k=0;k<B.c;++k)
Inc(C[i][k],mul(A[i][j],B[j][k]));
return C;
}
}P[64],Ans;
inline void init_1(){
for(int re i=0;i<=K;++i){
int inv=quickpow(i+1,mod-2);
P[0][id1[i]][id1[i]]=inv;
if(i)P[0][id1[i]][id1[i-1]]=mul(inv,i);
P[0][id1[i]][SIZE]=inv;
}
P[0][SIZE][SIZE]=1;P[0].r=SIZE+1,P[0].c=SIZE+1;
}
inline void init_2(){
for(int re i=0;i<=K;++i)for(int re j=0;j+i<=K;++j){
int inv=quickpow(i+j+1,mod-2);
P[0][id2[i][j]][id2[i][j]]=inv;
if(i)P[0][id2[i][j]][id2[i-1][j]]=mul(inv,i);
if(j)P[0][id2[i][j]][id2[i+1][j-1+(i+j<K)]]=mul(inv,j);
P[0][id2[i][j]][SIZE]=inv;
}
P[0][SIZE][SIZE]=1;P[0].r=SIZE+1,P[0].c=SIZE+1;
}
inline void init_3(){
for(int re i=0;i<=K;++i)for(int re j=0;i+j<=K;++j)for(int re k=0;i+j+k<=K;++k){
int inv=quickpow(i+j+k+1,mod-2);
P[0][id3[i][j][k]][id3[i][j][k]]=inv;
if(i)P[0][id3[i][j][k]][id3[i-1][j][k]]=mul(inv,i);
if(j)P[0][id3[i][j][k]][id3[i+1][j-1][k+(i+j+k<K)]]=mul(inv,j);
if(k)P[0][id3[i][j][k]][id3[i][j+1][k-1+(i+j+k<K)]]=mul(inv,k);
P[0][id3[i][j][k]][SIZE]=inv;
}
P[0][SIZE][SIZE]=1;P[0].r=SIZE+1,P[0].c=SIZE+1;
}
signed main(){
T=getint(),m=getint(),K=getint();
dfs(1,K);
switch(m){
case 1:init_1();break;
case 2:init_2();break;
case 3:init_3();break;
}
for(int re i=1;i<64;++i)P[i]=P[i-1]*P[i-1];
while(T--){
ll n=getint();
Ans=matrix(1,SIZE+1);
switch(m){
case 1:Ans[0][id1[1]]=1;break;
case 2:Ans[0][id2[0][1]]=1;break;
case 3:Ans[0][id3[0][0][1]]=1;break;
}
for(int re i=63;~i;--i)if(n>>i&1)Ans=Ans*P[i];
cout<<Ans[0][SIZE]<<"\n";
}
return 0;
}