【期望+矩阵乘法】LOJ2325 [清华集训 2017] 小 Y 和恐怖的奴隶主

版权声明:这是蒟蒻的BLOG,神犇转载也要吱一声哦~ https://blog.csdn.net/Dream_Lolita/article/details/85223502

【题目】
原题地址
BOSS \text{BOSS} 初始有一个 m m 点生命值的奴隶主,它随从上限是 K K ,你会进行 n n 次攻击,求期望 BOSS \text{BOSS} 扣多少血, T T 组数据,每组数据 m , k m,k 相等。 T 1000 m 3 , K 8 , n 1 0 18 T\leq 1000 m\leq 3,K\leq 8,n\leq 10^{18}
炉宗赛高!
【解题思路】
首先发现这个 n n 很大,估计是个矩乘,这个 k k m m 很小,估计是个状压,于是思路就确定了。

接下来发现我们只关心剩余 1 , 2 , 3 1,2,3 血的奴隶主各有多少个,我们可以考虑用期望的定义来求。那么设 f i , j , k , l f_{i,j,k,l} 表示第 i i 轮时,剩余 1 , 2 , 3 1,2,3 血量的奴隶主分别是 j , k , l j,k,l 个,那么这个的答案贡献就是 f i , j , k , l j + k + l + 1 \frac {f_{i,j,k,l}} {j+k+l+1}

我们打表可以知道状态数为 i = 0 k C i + m 1 m 1 \sum\limits_{i=0}^kC_{i+m-1}^{m-1} ,加上统计答案的计数器一共只有166种,这样每组数据暴力做 O ( T S 3 log n ) O(TS^3\log n) ,并不能过。观察到转移矩阵是一样的,于是我们预处理出 2 k 2^k 的矩阵,这样复杂度就是 O ( S 3 log n + T S 2 log n ) O(S^3\log n+TS^2\log n)

算起来还是十分卡卡卡卡常。

【参考代码】

#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;
}

猜你喜欢

转载自blog.csdn.net/Dream_Lolita/article/details/85223502
今日推荐