「清华集训 2017」小 Y 和恐怖的奴隶主
「清华集训 2017」小 Y 和恐怖的奴隶主
传送门
题解
讲道理,这是一道简单题.
首先可以考虑暴力\(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;
}