解题思路:
设 p[i][j][k][l] p [ i ] [ j ] [ k ] [ l ] 表示 i i 回合奴隶主 血剩余情况为 j、k、l j 、 k 、 l 的概率,那么对答案的贡献就是 p[i][j][k][l]j+k+l+1 p [ i ] [ j ] [ k ] [ l ] j + k + l + 1 。
先预处理出状态及转移,共有165种状态,加上求和的一行就166,再用矩阵快速幂。
注意多组询问,考虑到一个行向量乘以一个方阵的时间时
O(n2)
O
(
n
2
)
的,因此可以倍增预处理出转移矩阵的
2i
2
i
次幂,然后把每个矩阵依次乘到行向量上即可。
时间复杂度为 O(1663logn+T1662logn) O ( 166 3 l o g n + T 166 2 l o g n ) ,注意细节
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll getint()
{
ll i=0,f=1;char c;
for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar());
if(c=='-')c=getchar(),f=-1;
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
const int N=170,mod=998244353;
inline void add(ll &x,int y){x=x+y>=mod?x+y-mod:x+y;}
int T,m,k,tot,id[10][10][10],vis[10][10][10];
struct matrix
{
ll a[N][N];
matrix(){memset(a,0,sizeof(a));}
inline friend matrix operator * (const matrix &A,const matrix &B)
{
matrix res;
for(int i=0;i<=tot;i++)
for(int k=0;k<=tot;k++)if(A.a[i][k])
for(int j=0;j<=tot;j++)
res.a[i][j]=(res.a[i][j]+A.a[i][k]*B.a[k][j])%mod;
return res;
}
}A,B,P[65];
ll Pow(ll x,int y)
{
ll res=1;
for(;y;y>>=1,x=x*x%mod)
if(y&1)res=res*x%mod;
return res;
}
void dfs(int c1,int c2,int c3)
{
if(c1+c2+c3>k||id[c1][c2][c3])return;
id[c1][c2][c3]=tot++;
if(m>=1)dfs(c1+1,c2,c3);
if(m>=2)dfs(c1,c2+1,c3);
if(m>=3)dfs(c1,c2,c3+1);
}
void dfs1(int c1,int c2,int c3)
{
if(c1+c2+c3>k||vis[c1][c2][c3])return;
vis[c1][c2][c3]=1;ll inv=Pow(1+c1+c2+c3,mod-2);
ll p0=inv,p1=c1*inv%mod,p2=c2*inv%mod,p3=c3*inv%mod;
add(B.a[id[c1][c2][c3]][tot],p0);
add(B.a[id[c1][c2][c3]][id[c1][c2][c3]],p0);
if(c1)add(B.a[id[c1][c2][c3]][id[c1-1][c2][c3]],p1);
if(c2)
{
if(c1+c2+c3<k)
{
if(m==2)add(B.a[id[c1][c2][c3]][id[c1+1][c2][c3]],p2);
if(m==3)add(B.a[id[c1][c2][c3]][id[c1+1][c2-1][c3+1]],p2);
}
else add(B.a[id[c1][c2][c3]][id[c1+1][c2-1][c3]],p2);
}
if(c3)
{
if(c1+c2+c3<k)add(B.a[id[c1][c2][c3]][id[c1][c2+1][c3]],p3);
else add(B.a[id[c1][c2][c3]][id[c1][c2+1][c3-1]],p3);
}
if(m>=1)dfs1(c1+1,c2,c3);
if(m>=2)dfs1(c1,c2+1,c3);
if(m>=3)dfs1(c1,c2,c3+1);
}
void solve(ll n)
{
memset(A.a,0,sizeof(A.a));
if(m==1)A.a[0][id[1][0][0]]=1;
if(m==2)A.a[0][id[0][1][0]]=1;
if(m==3)A.a[0][id[0][0][1]]=1;
for(int i=0;i<=60;i++)
if(n>>i&1)A=A*P[i];
cout<<A.a[0][tot]<<'\n';
}
int main()
{
//freopen("lx.in","r",stdin);
T=getint(),m=getint(),k=getint();
dfs(0,0,0),dfs1(0,0,0);B.a[tot][tot]=1;
P[0]=B;for(int i=1;i<=60;i++)P[i]=P[i-1]*P[i-1];
while(T--)solve(getint());
return 0;
}