【题目】
原题地址
BOSS
\text{BOSS}
BOSS初始有一个
m
m
m点生命值的奴隶主,它随从上限是
K
K
K,你会进行
n
n
n次攻击,求期望
BOSS
\text{BOSS}
BOSS扣多少血,
T
T
T组数据,每组数据
m
,
k
m,k
m,k相等。
T
≤
1000
m
≤
3
,
K
≤
8
,
n
≤
1
0
18
T\leq 1000 m\leq 3,K\leq 8,n\leq 10^{18}
T≤1000m≤3,K≤8,n≤1018
炉宗赛高!
【解题思路】
首先发现这个
n
n
n很大,估计是个矩乘,这个
k
k
k和
m
m
m很小,估计是个状压,于是思路就确定了。
接下来发现我们只关心剩余 1 , 2 , 3 1,2,3 1,2,3血的奴隶主各有多少个,我们可以考虑用期望的定义来求。那么设 f i , j , k , l f_{i,j,k,l} fi,j,k,l表示第 i i i轮时,剩余 1 , 2 , 3 1,2,3 1,2,3血量的奴隶主分别是 j , k , l j,k,l j,k,l个,那么这个的答案贡献就是 f i , j , k , l j + k + l + 1 \frac {f_{i,j,k,l}} {j+k+l+1} j+k+l+1fi,j,k,l。
我们打表可以知道状态数为 ∑ i = 0 k C i + m − 1 m − 1 \sum\limits_{i=0}^kC_{i+m-1}^{m-1} i=0∑kCi+m−1m−1,加上统计答案的计数器一共只有166种,这样每组数据暴力做 O ( T S 3 log n ) O(TS^3\log n) O(TS3logn),并不能过。观察到转移矩阵是一样的,于是我们预处理出 2 k 2^k 2k的矩阵,这样复杂度就是 O ( S 3 log n + T S 2 log n ) O(S^3\log n+TS^2\log n) O(S3logn+TS2logn)
算起来还是十分卡卡卡卡常。
【参考代码】
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=10,S=170,mod=998244353;
int T,m,K,tot;
int f[N][N],g[N][N][N];
ll n,ans[S],t[S];
ll read()
{
ll ret=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return ret;
}
ll qpow(ll x,ll y){ll res=1;for(;y;y>>=1,x=x*x%mod)if(y&1)res=res*x%mod;return res;}
struct Matrix
{
ll v[S][S];
void clear(){memset(v,0,sizeof(v));}
void one(){for(int i=0;i<S;++i)v[i][i]=1;}
Matrix operator * (const Matrix&a)const
{
Matrix res;res.clear();
for(int i=1;i<=tot;++i) for(int j=1;j<=tot;++j) for(int k=1;k<=tot;++k)
res.v[i][j]=(res.v[i][j]+v[i][k]*a.v[k][j])%mod;
return res;
}
}A[60];
void mul(ll *a,const Matrix&b)
{
memset(t,0,sizeof(t));
for(int i=1;i<=tot;++i) for(int j=1;j<=tot;++j)
t[j]=(t[j]+a[i]*b.v[i][j])%mod;
for(int i=1;i<=tot;++i) a[i]=t[i];
}
void init1(){tot=3;A[0].v[3][1]=A[0].v[3][2]=A[0].v[3][3]=qpow(2,mod-2);}
void init2()
{
for(int i=0;i<=K;++i) for(int j=0;j<=K;++j)
if(i+j<=K) f[i][j]=++tot;
for(int i=0;i<=K;++i) for(int j=0;j<=K;++j) if(i+j<=K)
{
ll inv=qpow(i+j+1,mod-2);
A[0].v[f[i][j]][1]=A[0].v[f[i][j]][f[i][j]]=inv;
if(i) A[0].v[f[i][j]][f[i-1][j]]=inv*i%mod;
if(j)
{
if(i+j<K) A[0].v[f[i][j]][f[i+1][j]]=inv*j%mod;
else A[0].v[f[i][j]][f[i+1][j-1]]=inv*j%mod;
}
}
}
void init3()
{
for(int i=0;i<=K;++i) for(int j=0;j<=K;++j) for(int k=0;k<=K;++k)
if(i+j+k<=K) g[i][j][k]=++tot;
for(int i=0;i<=K;++i) for(int j=0;j<=K;++j) for(int k=0;k<=K;++k) if(i+j+k<=K)
{
ll inv=qpow(i+j+k+1,mod-2);
A[0].v[g[i][j][k]][1]=A[0].v[g[i][j][k]][g[i][j][k]]=inv;
if(i) A[0].v[g[i][j][k]][g[i-1][j][k]]=inv*i%mod;
if(j)
{
if(i+j+k<K) A[0].v[g[i][j][k]][g[i+1][j-1][k+1]]=inv*j%mod;
else A[0].v[g[i][j][k]][g[i+1][j-1][k]]=inv*j%mod;
}
if(k)
{
if(i+j+k<K) A[0].v[g[i][j][k]][g[i][j+1][k]]=inv*k%mod;
else A[0].v[g[i][j][k]][g[i][j+1][k-1]]=inv*k%mod;
}
}
}
void solve()
{
for(int i=1;i<60;++i) A[i]=A[i-1]*A[i-1];
while(T--)
{
n=read();memset(ans,0,sizeof(ans));ans[3]=1;
for(int i=0;i<60;++i) if(n&((ll)1<<i)) mul(ans,A[i]);
printf("%lld\n",ans[1]);
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("LOJ2325.in","r",stdin);
freopen("LOJ2325.out","w",stdout);
#endif
T=read();m=read();K=read();tot=1;
A[0].v[1][1]=A[0].v[2][1]=A[0].v[2][2]=1;
if(m==1) init1();
else if(m==2) init2();
else init3();
solve();
return 0;
}