P4007 小 Y 和恐怖的奴隶主
P4007 小 Y 和恐怖的奴隶主
对于一个boss,有若干随从,每个随从血量小于m,(m$\le\(3),如果打一名随从没有死,就会产生一名新的随从,随从上限数为k\)(k\le8)$,每一轮随机对一名敌人造成一点伤害,m一定,T次询问求解n轮后对boss造成的伤害期望。
首先看到T次询问我们就能想到预处理转移矩阵的套路,通过预处理,将复杂度降低。
然后考虑dp,\(dp[i][j][k][p]\)表示i轮后场上有j个1血随从,k个2血随从,p个3血随从,然后每次按照题意转移即可,然后可以发现这个东西是线性的,所以可以考虑矩阵优化dp,然后由于k的大小,所以总共的状态只有165种,然后我们另开一个表示最后的答案,发现答案可以在转移过程中统计。
然后我们预处理出矩阵,每次询问只需要处理行向量乘方阵即可。
另外注意代码细节:
- ?:运算优先级非常低,仅高于赋值运算符,所以在大于小于号后面必须加上括号
- 属于高达1e18所以需要开LL
- 卡常数技巧,就是优先枚举较高维,提高运行速度。
#include<bits/stdc++.h>
#define LL long long
#define V inline void
#define I inline LL
#define FOR(i,a,b) for(register LL i=a,end##i=b;i<=end##i;++i)
#define REP(i,a,b) for(register LL i=a,end##i=b;i>=end##i;--i)
#define go(i,x) for(LL i=hed[x];i;i=e[i].pre)
using namespace std;
inline LL read()
{
char x='\0';
LL fh=1,sum=0;
for(x=getchar();x<'0'||x>'9';x=getchar())if(x=='-')fh=-1;
for(;x>='0'&&x<='9';x=getchar())sum=sum*10+x-'0';
return fh*sum;
}
const LL N=166+9,K=8+9;
const LL mod=998244353;
LL inv[N];
LL id[K][K][K],cnt;
struct matrix{
LL ju[N][N];
matrix(){memset(ju,0,sizeof(ju));}
LL* operator[](LL i){return ju[i];}
V print()
{
cout<<"print"<<endl;//
FOR(i,1,cnt)FOR(j,1,cnt)cout<<i<<' '<<j<<" "<<ju[i][j]<<endl;//
}
}M[70];
I add(LL x,LL y){return (x+y>=mod)?x+y-mod:x+y;}
matrix operator*(matrix a,matrix b)
{
matrix c;
FOR(k,1,cnt)FOR(i,1,cnt)FOR(j,1,cnt)
c[i][j]=add(c[i][j],1LL*a[i][k]*b[k][j]%mod);
return c;
}
I ksm(LL a,LL b)
{
LL sum=1;
while(b)
{
if(b&1)sum=1LL*sum*a%mod;
b>>=1;
a=1LL*a*a%mod;
}
return sum;
}
LL ans[N],tmp[N];
V Mul(LL p)
{
FOR(i,1,cnt)tmp[i]=0;
FOR(j,1,cnt)FOR(i,1,cnt)tmp[i]=add(tmp[i],1LL*ans[j]*M[p][j][i]%mod);
FOR(i,1,cnt)ans[i]=tmp[i];
}
LL T,m,k;
int main()
{
T=read(),m=read(),k=read();
FOR(i,1,9)inv[i]=ksm(i,mod-2);
for(LL a=0;a<=k;a++)
for(LL b=0;b<=(m>=2?k-a:0);b++)
for(LL c=0;c<=(m>=3?k-a-b:0);c++)
{
id[a][b][c]=++cnt;
// cout<<"cnt "<<a<<' '<<b<<' '<<c<<" "<<cnt<<endl;
}
++cnt;
// cout<<cnt<<endl;//
M[0][cnt][cnt]=1;
for(LL a=0;a<=k;a++)
for(LL b=0;b<=(m>=2?k-a:0);b++)
for(LL c=0;c<=(m>=3?k-a-b:0);c++)
{
LL i=id[a][b][c],iv=inv[a+b+c+1],add=a+b+c<k;
if(m==1)
{
if(a)M[0][i][id[a-1][b][c]]=1LL*a*iv%mod;
}
if(m==2)
{
if(a)M[0][i][id[a-1][b][c]]=1LL*a*iv%mod;
if(b)M[0][i][id[a+1][b-1+add][c]]=1LL*b*iv%mod;
}
if(m==3)
{
if(a)M[0][i][id[a-1][b][c]]=1LL*a*iv%mod;
if(b)M[0][i][id[a+1][b-1][c+add]]=1LL*b*iv%mod;
if(c)M[0][i][id[a][b+1][c-1+add]]=1LL*c*iv%mod;
}
M[0][i][i]=M[0][i][cnt]=iv;
}
// cout<<cnt<<endl;//
// M[0].print();
for(LL i=1;i<=60;i++)M[i]=M[i-1]*M[i-1];
while(T--)
{
LL n=read();
FOR(i,1,cnt)ans[i]=0;
ans[id[m==1][m==2][m==3]]=1;
// cout<<"id "<<id[m==1][m==2][m==3]<<endl;//
FOR(i,0,60)if((n>>i)&1)Mul(i);
printf("%lld\n",ans[cnt]);
}
return 0;
}