2018.10.16 uoj#340. 【清华集训2017】小 Y 和恐怖的奴隶主(矩阵快速幂优化dp)

版权声明:随意转载哦......但还是请注明出处吧: https://blog.csdn.net/dreaming__ldx/article/details/83090116

传送门
一道不错的矩阵快速幂优化 d p dp
f [ i ] [ j ] [ k ] [ l ] f[i][j][k][l] 表示前 i i 轮第 i i 轮还有 j j 个一滴血的, k k 个两滴血的, l l 个三滴血的。
显然是可以从 f [ i 1 ] f[i-1] 转移过来的。
但是仔细一想,这个递推关系在 i = 1 i=1 ~ n n 的时候都是一样的,于是把后面三个状压上矩阵快速幂优化就行了。
直接转是 O ( T s i z e 3 l o g ) O(T*size^3log) 的。
于是可以用倍增的思想预处理出 l o g log 个数组,最后乘起来,由于结构相同可以做到 O ( s i z e s i z e l o g n T + s i z e s i z e s i z e l o g n ) O(size*size*log_n*T+size*size*size*log_n)
注意卡常优化。
代码:

#include<bits/stdc++.h>
#define Len 170
#define mod 998244353
#define ll unsigned long long
using namespace std;
int T,m,K,id[15][15][15],tot=0;
ll inv[15],ans[Len],n,tmp[Len];
const ll inf=16940360401038606353llu;
inline ll read(){
	ll ans=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
	return ans;
}
inline void write(const ll&x){
	if(x>9)write(x/10);
	putchar((x-x/10*10)^48);
}
struct Matrix{
	ll val[Len][Len];
	inline void init(){memset(val,0,sizeof(val));}
}f[65];
inline Matrix operator*(const Matrix&a,const Matrix&b){
	Matrix ret;
	ret.init();
	for(int i=1;i<=tot+1;++i)for(int k=1;k<=tot+1;++k)
		for(int j=1;j<=tot+1;++j){{
			ret.val[i][j]+=a.val[i][k]*b.val[k][j];
			if(ret.val[i][j]>=inf)ret.val[i][j]-=inf;
		}
	}
	for(int i=1;i<=tot+1;++i)for(int j=1;j<=tot+1;++j)ret.val[i][j]%=mod;
	return ret;
}
inline void update(const Matrix&a){
	memset(tmp,0,sizeof(tmp));
	for(int i=1;i<=tot+1;++i){
		for(int j=1;j<=tot+1;++j){
			tmp[i]+=ans[j]*a.val[j][i];
			if(tmp[i]>=inf)tmp[i]-=inf;
		}
		tmp[i]%=mod;
	}
	memcpy(ans,tmp,sizeof(tmp));
}
int main(){
	T=read(),m=read(),K=read(),inv[0]=inv[1]=1;
	for(int i=2;i<=10;++i)inv[i]=(mod-mod/i)*inv[mod%i]%mod;
	for(int i=0;i<=K;++i)for(int j=0;j<=(m>1?K-i:0);++j)for(int k=0;k<=(m>2?K-i-j:0);++k)id[i][j][k]=++tot;
	for(int i=0;i<=K;++i)for(int j=0;j<=(m>1?K-i:0);++j)for(int k=0;k<=(m>2?K-i-j:0);++k){
		int pos=id[i][j][k],t=(i+j+k)<K;
		if(m==1)if(i)f[0].val[pos][id[i-1][j][k]]=inv[i+1]*i%mod;
		if(m==2){
			if(i)f[0].val[pos][id[i-1][j][k]]=inv[i+j+1]*i%mod;
			if(j)f[0].val[pos][id[i+1][j+t-1][k]]=inv[i+j+1]*j%mod;
		}
		if(m==3){
			if(i)f[0].val[pos][id[i-1][j][k]]=inv[i+j+k+1]*i%mod;
			if(j)f[0].val[pos][id[i+1][j-1][k+t]]=inv[i+j+k+1]*j%mod;
			if(k)f[0].val[pos][id[i][j+1][k+t-1]]=inv[i+j+k+1]*k%mod;
		}
		f[0].val[pos][pos]=f[0].val[pos][tot+1]=inv[i+j+k+1];
	}	
	f[0].val[tot+1][tot+1]=1;
	for(int i=1;i<=63;++i)f[i]=f[i-1]*f[i-1];
	while(T--){
		n=read(),memset(ans,0,sizeof(ans));
		switch(m){
			case 1:ans[id[1][0][0]]=1;break;
			case 2:ans[id[0][1][0]]=1;break;
			case 3:ans[id[0][0][1]]=1;break;
		}
		for(int i=0;n;n>>=1,++i)if(n&1)update(f[i]);
		write(ans[tot+1]),puts("");
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/dreaming__ldx/article/details/83090116