「清华集训 2017」小 Y 和恐怖的奴隶主

「清华集训 2017」小 Y 和恐怖的奴隶主

传送门

Loj

题解

讲道理,这是一道简单题.

首先可以考虑暴力\(dp\),很显然可以设\(f_{i,a,b,c}\)表示\(i\)次攻击后,有\(a\)个一滴血的随从,\(b\)个两滴血的,\(c\)个三滴血的.

然后这个东西状态最多\(166\),考虑直接矩阵快速幂.

注意到这是一个行向量\(\times\)矩阵,所以复杂度是\(O(k^2logn)\),其他的矩阵预处理即可.

代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<iostream>
using namespace std;
#define ll long long
#define REP(a,b,c) for(int a=b;a<=c;a++)
#define re register
#define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
typedef pair<int,int> pii;
#define mp make_pair
inline int gi()
{
	int f=1,sum=0;char ch=getchar();
	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
	return f*sum;
}
const int N=210,Mod=998244353;
int a[N],A[N],m,k,tot,lim[4],Hash[19][19][19],mat[62][N][N],tmp[N];
ll n;
void dfs(int a,int b,int c)
{
	if(a>lim[1]||b>lim[2]||c>lim[3])return;
	if(Hash[a][b][c]||a+b+c>k)return;
	Hash[a][b][c]=++tot;
	dfs(a+1,b,c);dfs(a,b+1,c);dfs(a,b,c+1);
}
int qpow(int a,int b){int ret=1;while(b){if(b&1)ret=1ll*ret*a%Mod;b>>=1;a=1ll*a*a%Mod;}return ret;}
void calc(int &a,int &b,int &c){(m==1)?a++:(m==2)?b++:c++;}
void init()
{
	for(int a=0;a<=lim[1];a++)
		for(int b=0;b+a<=k&&b<=lim[2];b++)
			for(int c=0;a+b+c<=k&&c<=lim[3];c++)
			{
				int s=a+b+c+1,p=Hash[a][b][c];
				mat[0][p][tot+1]=(mat[0][p][tot+1]+qpow(s,Mod-2))%Mod;
				mat[0][p][p]=(mat[0][p][p]+qpow(s,Mod-2))%Mod;
				if(a)
				{
					int ta=a-1,tb=b,tc=c;
					mat[0][p][Hash[ta][tb][tc]]=(mat[0][p][Hash[ta][tb][tc]]+1ll*qpow(s,Mod-2)*a%Mod)%Mod;
				}
				if(b)
				{
					int ta=a+1,tb=b-1,tc=c;if(s<=k)calc(ta,tb,tc);
					mat[0][p][Hash[ta][tb][tc]]=(mat[0][p][Hash[ta][tb][tc]]+1ll*qpow(s,Mod-2)*b%Mod)%Mod;
				}
				if(c)
				{
					int ta=a,tb=b+1,tc=c-1;if(s<=k)calc(ta,tb,tc);
					mat[0][p][Hash[ta][tb][tc]]=(mat[0][p][Hash[ta][tb][tc]]+1ll*qpow(s,Mod-2)*c%Mod)%Mod;
					
				}
			}
	mat[0][tot+1][tot+1]=(mat[0][tot+1][tot+1]+1)%Mod;
	A[Hash[m==1][m==2][m==3]]=1;
	for(int p=1;p<=60;p++)
		for(int i=1;i<=tot+1;i++)
			for(int k=1;k<=tot+1;k++)
				for(int j=1;j<=tot+1;j++)
					mat[p][i][j]=(mat[p][i][j]+1ll*mat[p-1][i][k]*mat[p-1][k][j]%Mod)%Mod;
}
int main()
{
	int T=gi();m=gi();k=gi();
	for(int i=1;i<=m;i++)lim[i]=k;
	dfs(0,0,0);init();
	while(T--)
	{
		scanf("%lld",&n);int b=0;
		for(int i=1;i<=tot+1;i++)a[i]=A[i];
		while(n)
		{
			if(n&1ll)
			{
				for(int i=1;i<=tot+1;i++)tmp[i]=a[i],a[i]=0;
				for(int k=1;k<=tot+1;k++)
					for(int j=1;j<=tot+1;j++)
						a[j]=(a[j]+1ll*tmp[k]*mat[b][k][j]%Mod)%Mod;
			}
			b++;n>>=1ll;
		}
		printf("%d\n",a[tot+1]);
	}
	return 0;
}
posted @ 2020-05-09 08:26  fexuile  阅读(145)  评论(0编辑  收藏  举报