【省選模擬】20/04/13 擺傢俱(分治)(DP)(矩陣 / BM)

傳送門

  • 思路:暴力的做法就是枚舉末狀態,處理到末狀態的方案數
    發現方案數只和有幾位不同有關,可以用分治 + dpdp 處理出 fi,jf_{i,j} 表示和 iijj 位不同的數的和,複雜度 O(k2nk)O(k^2n^k)
    下面考慮處理係數,設 dpi,jdp_{i,j} 表示走 ii 步,還有 jj 個不同的方案數
    那麼轉移可以表示成矩陣的形式,於是可以暴力前 2k2k 項跑 BMBM
    處理出線性遞推式過後 bsgsbsgs,那麼最後的複雜度就是 O(qk2)O(qk^2)
#include<bits/stdc++.h>
#define cs const
#define pb push_back
#define poly vector<int> 
using namespace std;
namespace IO{
	cs int Rlen=1<<22|1;
	inline char gc(){
		static char buf[Rlen],*p1,*p2;
		(p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin));
		return p1==p2?EOF:*p1++;
	}
	int read(){
		int x=0; char c=gc(); bool f=false;
		while(!isdigit(c)) f=(c=='-'),c=gc();
		while(isdigit(c)) x=(((x<<2)+x)<<1)+(c^48), c=gc();
		return f?-x:x;
	}
} using namespace IO;
cs int Mod = 998244353;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b; }
int dec(int a, int b){ return a - b < 0 ? a - b + Mod : a - b; }
int mul(int a, int b){ return 1ll * a * b % Mod; }
void Add(int &a, int b){ a = add(a,b); }
void Dec(int &a, int b){ a = dec(a,b); }
void Mul(int &a, int b){ a = mul(a,b); }
int ksm(int a, int b){ int as=1; for(;b;b>>=1,Mul(a,a)) if(b&1) Mul(as,a); return as; }
cs int N = 1e6 + 5, M = 25;
int n, K, q, S, a[N];
int f[N][M];
void work(){
	for(int i=0; i<S; i++) f[i][0]=a[i];
	for(int i=1,u=1; i<S; i*=n, ++u){
		for(int t=u; t>=1; t--)
		for(int j=0; j<S; j+=i*n){
			static int Sm[N]; 
			memset(Sm,0,sizeof(int)*i);
			for(int k=0; k<i; k++)
			for(int l=j+k; l<j+i*n; l+=i) Add(Sm[k],f[l][t-1]);
			for(int k=0; k<i*n; k++){
				int coe=dec(Sm[k%i],f[j+k][t-1]);
				Add(f[j+k][t],coe);
			}
		}
	}
}
namespace BM{
	int a[M<<2]; poly cur, bst; int vl=0, fail=0;
	void operator += (poly &a, poly b){ 
		if(a.size()<b.size()) a.resize(b.size());
		for(int i=0; i<(int)b.size(); i++) Add(a[i],b[i]);
	}
	void extend(int n){
		int t=a[n];
		for(int i=1; i<(int)cur.size(); i++) Dec(t,mul(cur[i],a[n-i]));
		if(!t) return; 
		if(cur.empty()){ cur.resize(n+1); fail=n; vl=t; return; }
		int coe=mul(t,ksm(vl,Mod-2));
		poly nxt(n-fail,0); nxt.pb(coe);
		for(int i=1; i<(int)bst.size(); i++) nxt.pb(mul(coe,dec(0,bst[i])));
		nxt+=cur; 
		if((int)cur.size()-n<=(int)bst.size()-fail) bst=cur, fail=n, vl=t;
		cur=nxt;
	}
}
cs int W = 1e3 + 50;
poly pw1[W], pw2[W], pw3[W], mod;
poly polymul(poly a, poly b){
	int deg=a.size()+b.size()-1; poly c(deg,0);
	for(int i=0; i<(int)a.size(); i++)
	for(int j=0; j<(int)b.size(); j++)
	Add(c[i+j],mul(a[i],b[j]));
	for(int i=deg-1; i>=(int)mod.size()-1; i--) if(c[i]){
		for(int j=mod.size()-2,k=i-1;~j;j--,k--) 
		Dec(c[k],mul(c[i],mod[j]));
	} if(deg>mod.size()-1) c.resize(mod.size()-1); return c;
}
void work_BSGS(){ 
	static int dp[M<<2][M];
	int u=K+K+5; BM::a[1]=dp[0][0]=1;
	BM::extend(1);
	for(int i=1; i<=u; i++){
	for(int j=0; j<=K; j++){
		if(j) Add(dp[i][j],mul(dp[i-1][j-1],mul(K-j+1,n-1)));
		Add(dp[i][j],mul(dp[i-1][j],mul(j,n-2)));
		Add(dp[i][j],mul(dp[i-1][j+1],j+1));
	} BM::a[i+1]=dp[i][0]; BM::extend(i+1);
	} mod=BM::cur; reverse(mod.begin(),mod.end());
	for(int i=0; i<(int)mod.size(); i++) mod[i]=dec(0,mod[i]);
	mod.back()=1; assert(mod.size()<=K+5);
	pw1[0].pb(1); pw1[1].pb(0); pw1[1].pb(1);
	for(int i=2; i<=1000; i++) pw1[i]=polymul(pw1[i-1],pw1[1]);
	pw2[0].pb(1); pw2[1]=pw1[1000];
	for(int i=2; i<=1000; i++) pw2[i]=polymul(pw2[i-1],pw2[1]);
	pw3[0].pb(1); pw3[1]=pw2[1000];
	for(int i=2; i<=1000; i++) pw3[i]=polymul(pw3[i-1],pw3[1]);
}
int g[M][M<<1][M];
int main(){
	#ifdef FSYolanda
	freopen("b.in","r",stdin);
	freopen("b.out","w",stdout);
	#endif
	n=read(), K=read(), q=read(); S=ksm(n,K); 
	for(int i=0; i<S; i++) a[i]=read();
	work(); 
	work_BSGS();
	for(int T=0; T<=K; T++){
		g[T][0][T]=1;
		for(int i=1; i<(int)mod.size(); i++)
		for(int j=0; j<=K; j++){
			if(j) Add(g[T][i][j],mul(g[T][i-1][j-1],mul(K-j+1,n-1)));
			Add(g[T][i][j],mul(g[T][i-1][j],mul(j,n-2)));
			Add(g[T][i][j],mul(g[T][i-1][j+1],j+1));
		}
	}
	int Ans=1;
	while(q--){
		int a=read(), T=mul(read(),Ans), t=T, ans=0;
		poly coe=pw1[t%1000]; t/=1000;
		coe=polymul(coe,pw2[t%1000]); t/=1000;
		coe=polymul(coe,pw3[t]); 
		for(int i=0; i<=min(T,K); i++){
			int as=0;
			for(int j=0; j<(int)coe.size(); j++) if(coe[j])
			Add(as,mul(coe[j],g[i][j][0]));
			Add(ans,mul(f[a][i],as));
		} cout<<(Ans=ans)<<'\n';
	} return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章