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种,然后我们另开一个表示最后的答案,发现答案可以在转移过程中统计。

然后我们预处理出矩阵,每次询问只需要处理行向量乘方阵即可。

另外注意代码细节:

  1. ?:运算优先级非常低,仅高于赋值运算符,所以在大于小于号后面必须加上括号
  2. 属于高达1e18所以需要开LL
  3. 卡常数技巧,就是优先枚举较高维,提高运行速度。
#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;
}

posted @ 2021-03-08 22:51  dinlon  阅读(99)  评论(0)    收藏  举报