版权声明:这是蒟蒻的BLOG,神犇转载也要吱一声哦~ https://blog.csdn.net/Dream_Lolita/article/details/85223502
【题目】
原题地址
初始有一个
点生命值的奴隶主,它随从上限是
,你会进行
次攻击,求期望
扣多少血,
组数据,每组数据
相等。
炉宗赛高!
【解题思路】
首先发现这个
很大,估计是个矩乘,这个
和
很小,估计是个状压,于是思路就确定了。
接下来发现我们只关心剩余 血的奴隶主各有多少个,我们可以考虑用期望的定义来求。那么设 表示第 轮时,剩余 血量的奴隶主分别是 个,那么这个的答案贡献就是 。
我们打表可以知道状态数为 ,加上统计答案的计数器一共只有166种,这样每组数据暴力做 ,并不能过。观察到转移矩阵是一样的,于是我们预处理出 的矩阵,这样复杂度就是
算起来还是十分卡卡卡卡常。
【参考代码】
#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;
}