1. 程式人生 > 其它 >P6800-[模板]Chirp Z-Transform【NTT】

P6800-[模板]Chirp Z-Transform【NTT】

正題

題目連結:https://www.luogu.com.cn/problem/P6800


題目大意

給出一個\(n\)此多項式\(P\),對於\(k\in[0,m-1]\)所有的求\(P(c^k)\)
輸出答案對\(998244353\)取模
\(1\leq n,m\leq 10^6\)


解題思路

\[g(n)=\sum_{i=0}^{n-1}a_ic^{i\times n} \]

然後根據\(i\times n=\binom{i+n}{2}-\binom{i}{2}-\binom{n}{2}\)

\[g(n)=c^{-\binom{n}{2}}\sum_{i=0}^{n-1}a_ic^{\binom{i+n}{2}}c^{-\binom{i}{2}} \]

然後這是一個反著卷積的形式,直接上NTT就好了

時間複雜度\(O(n\log n)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=4e6+10,P=998244353;
ll n,m,c,a[N],r[N],F[N],G[N];
ll power(ll x,ll b){
	ll ans=1;b%=P-1;
	while(b){
		if(b&1)ans=ans*x%P;
		x=x*x%P;b>>=1;
	}
	return ans;
}
ll C(ll n)
{return n*(n-1)/2;}
void NTT(ll *f,ll n,ll op){
	for(ll i=0;i<n;i++)
		if(i<r[i])swap(f[i],f[r[i]]);
	for(ll p=2;p<=n;p<<=1){
		ll tmp=power(3,(P+1)/p),len=p>>1;
		if(op==-1)tmp=power(tmp,P-2);
		for(ll k=0;k<n;k+=p){
			ll buf=1;
			for(ll i=k;i<k+len;i++){
				ll tt=f[i+len]*buf%P;
				f[i+len]=(f[i]-tt+P)%P;
				f[i]=(f[i]+tt)%P;
				buf=buf*tmp%P;
			}
		}
	}
	if(op==-1){
		ll invn=power(n,P-2);
		for(ll i=0;i<n;i++)
			f[i]=f[i]*invn%P;
	}
	return;
}
signed main()
{
	scanf("%lld%lld%lld",&n,&c,&m);
	ll inv=power(c,P-2);
	for(ll i=0;i<n;i++)
		scanf("%lld",&a[i]);
	for(ll i=0;i<n+m;i++)
		F[i]=power(c,C(n+m-i-1));
	for(ll i=0;i<n;i++)
		G[i]=a[i]*power(inv,C(i))%P;
	ll len=1;
	while(len<n+m)len<<=1;
	for(ll i=0;i<len;i++)
		r[i]=(r[i>>1]>>1)|((i&1)?(len>>1):0);
	NTT(F,len,1);NTT(G,len,1);
	for(ll i=0;i<len;i++)F[i]=F[i]*G[i]%P;
	NTT(F,len,-1);
	for(ll i=n+m-1;i>=n;i--)
		printf("%lld ",F[i]*power(inv,C(n+m-i-1))%P);
	return 0;
}