求调分治 FFT
查看原帖
求调分治 FFT
555065
ChrysanthBlossom楼主2024/3/9 18:02

似乎实现方法与题解的都不太一样,我为了方便强行把递推式枚举范围从 [2,n−2][2,n-2] 扩到了 [0,n−1][0,n-1] ,同时在算值的时候给他减了一下,还特意把 f0f_0 设成 00,但反正不管怎样他就是寄了(输出的 ff 完全不对),因此在这里求调一下。

NTT 应该是没问题的。

#include<bits/stdc++.h>
#define ri register int
#define ll long long
using namespace std;
const int maxn=1e5+5;
ll f[maxn];
int rev[maxn];
void init(int limit){
	for(ri i=1;i<limit;i++){
		rev[i]=((rev[i>>1]>>1)|(i&1?limit>>1:0));
	}
//	for(ri i=0;i<limit;i++)cout<<rev[i]<<' ';cout<<endl;
}
const int mod=998244353;
const int G=3;
ll qpow(ll a,ll b,ll p){
	ll ans=1;
	while(b){
		if(b&1)ans=ans*a%p;
		a=a*a%p;
		b>>=1;
	}
	return ans;
} 
const int invG=qpow(G,mod-2,mod);
//void NTT(ll f[],int limit,bool tp){
//	for(ri i=0;i<limit;i++){
//		if(i<rev[i])swap(f[rev[i]],f[i]);
//	}
//	for(ri len=2;len<=limit;len<<=1){
//		ll dwg=qpow(tp?G:invG,(mod-1)/len,mod);
//		int pa=len>>1;
//		for(ri i=0;i<limit;i+=len){
//			ll bf=1;
//			for(ri j=i;j<i+pa;j++){
//				ll t=bf*f[j+pa]%mod;
//				f[j+pa]=(f[j]-t+mod)%mod;
//				f[j]=(f[j]+t)%mod;
//				bf=bf*dwg%mod;
//			}
//		}
//	}
//}
void NTT(ll f[],int limit,bool tp){
	for(ri i=0;i<limit;i++){
		if(i<rev[i])swap(f[i],f[rev[i]]);
	}
	for(ri len=2;len<=limit;len<<=1){
		ll dwg=qpow(tp?G:invG,(mod-1)/len,mod);
		int pa=len>>1;
		for(ri i=0;i<limit;i+=len){
			ll bf=1;
			for(ri j=i;j<i+pa;j++){
				ll t=f[j+pa]*bf%mod;
				f[j+pa]=(f[j]-t+mod)%mod;
				f[j]=(f[j]+t)%mod;
				bf=bf*dwg%mod;
			}
		}
	}
	if(!tp){
		ll invn=qpow(limit,mod-2,mod);
		for(ri i=0;i<limit;i++){
			f[i]=(f[i]*invn)%mod;
		}
	}
}
ll A[maxn],B[maxn];
void test_times(){
	int n,m;
	cin>>n>>m;
	for(ri i=0;i<=n;i++)cin>>A[i];
	for(ri i=0;i<=m;i++)cin>>B[i];
	n+=m;
	int limit=1;
	while(limit<=n)limit<<=1;
//	cout<<limit<<endl;
	init(limit);
	NTT(A,limit,1);
	NTT(B,limit,1);
	for(ri i=0;i<limit;i++)A[i]=A[i]*B[i]%mod;
	NTT(A,limit,0);
	for(ri i=0;i<=n;i++){
		cout<<A[i]<<' ';
	}cout<<endl;
	exit(0);
}
void solve(int l,int r){
	if(l==r-1){
		if(l==0)f[l]=0;
		else if(l==1)f[l]=2;
		else{
			f[l]=(f[l]+(l-1)*f[l-1]%mod-(l-2)*f[l-1]%mod*f[1]%mod+mod)%mod;
		}
		return;
	}
	int mid=l+r>>1;
	solve(l,mid);
	int limit=r-l;
//	memset(A,0,sizeof(A));
//	memset(B,0,sizeof(B));
	if(l){
		for(ri i=0;i<r-l;i++){
			A[i]=f[l+i]*(l+i-1)%mod;
			if(i+l>=mid)A[i]=0;
		}
		for(ri i=0;i<r-l;i++){
			B[i]=f[i];
	//		if(i+l>=mid)B[i]=0;
		}
		init(r-l);
		NTT(A,r-l,1);
		NTT(B,r-l,1);
		for(ri i=0;i<r-l;i++){
			A[i]=A[i]*B[i]%mod;
		}
		NTT(A,r-l,0);
		for(ri i=mid-l;i<r-l;i++){
			f[i+l]=(f[i+l]+A[i])%mod;
		}
		
		for(ri i=0;i<r-l;i++){
			A[i]=f[l+i];
			if(i+l>=mid)A[i]=0;
		}
		for(ri i=0;i<r-l;i++){
			B[i]=f[i]*(i-1)%mod;
	//		if(i+l>=mid)B[i]=0;
		}
		init(r-l);
		NTT(A,r-l,1);
		NTT(B,r-l,1);
		for(ri i=0;i<r-l;i++){
			A[i]=A[i]*B[i]%mod;
		}
		NTT(A,r-l,0);
		for(ri i=mid-l;i<r-l;i++){
			f[i+l]=(f[i+l]+A[i])%mod;
		}
	}
	else{
		for(ri i=0;i<mid;i++){
			A[i]=f[i]*(i-1)%mod;
		}
		for(ri i=0;i<mid;i++){
			B[i]=f[i];
		}
		for(ri i=mid;i<r;i++){
			A[i]=B[i]=0;
		}
		NTT(A,r-l,1);
		NTT(B,r-l,1);
		for(ri i=0;i<r-l;i++){
			A[i]=A[i]*B[i]%mod;
		}
		NTT(A,r-l,0);
		for(ri i=mid;i<r;i++){
			f[i]=(f[i]+A[i])%mod;
		}
	}
	solve(mid,r);
}
int T,n;
int a[maxn];
struct my_stack{
	int tot;
	int num[maxn];
	void push(int x){
		num[++tot]=x;
	}
	void pop(){
		--tot;
	}
	void clear(){
		tot=0;
	}
	int top(){
		return num[tot];
	}
}st;
vector<int>vec[maxn];
ll calc_ans(){	
	for(ri i=1;i<=n;i++){
		cin>>a[i];
	}
	for(ri i=1;i<=n;i++){
		vec[i].clear();
	}
	for(ri i=n;i;i--){
		if(i-a[i]+1>0)vec[i-a[i]+1].push_back(i);
	}
	if(a[n]!=n)return 0;
	ll ans=1;
	for(ri i=1;i<=n;i++){
		for(auto x:vec[i]){
			st.push(x);
		}
		if(st.top()!=i){
			return 0;
		}
		else{
			st.pop();
		}
	}
	for(ri i=1;i<=n;i++){
		for(auto x:vec[i]){
			st.push(x-a[x]+1);
		}
		int cnt=0;
		while(st.top()!=i-a[i]+1){
			st.pop();
			cnt++;
		}
		ans=ans*f[cnt]%mod;
	}
	return ans;
}
signed main(){
	ios::sync_with_stdio(0);
//	test_times();
	cin>>T>>n;
	int limit=1;
	while(limit<=n){
		limit<<=1;
	}
	solve(0,limit);
	f[0]=1;
//	for(ri i=0;i<limit;i++){
//		cout<<f[i]<<' ';
//	}cout<<endl;
	while(T--){
		cout<<calc_ans()<<endl;
	}
	return 0;
}
2024/3/9 18:02
加载中...