多项式大学习???

在省选前认为省选会考哈集幂或者多项式,于是加训。结果最后一个都没考。

我们优秀的非多项式复杂度题呢,怎么没了[举牌牌]

所以最后总结一下加训的东西吧。


我们有 应该全文背诵的 NTT 板子:

const int mod=998244353,iG=(mod+1)/3;
int r[1<<22];
void NTT(int *A,int lim,int op){
	for(int i=0;i<lim;i++)if(i<r[i])swap(A[i],A[r[i]]);
	for(int mid=1;mid<lim;mid<<=1){
		int w=ksm(op?iG:3,(mod-1)/(mid<<1));
		for(int i=0;i<lim;i+=(mid<<1)){
			int p=1;
			for(int j=0;j<mid;j++,p=p*w%mod){
				int u=A[i+j],v=p*A[i+mid+j]%mod;
				A[i+j]=(u+v)%mod;
				A[i+mid+j]=(u+mod-v)%mod;
			}
		}
	}
	if(op){
		int I=ksm(lim,mod-2);
		for(int i=0;i<lim;i++)A[i]=A[i]*I%mod;
	}
}

提问:这段话是在干什么?

如果我们学过 FFT(快速傅里叶变换)的话,这个问题很容易回答。FFT 的作用是将多项式快速转换为点值,而 NTT 是将变换转到了模素数域上求点值。相当于给定了一个多项式 \(A\),NTT 将 \(A\) 转换成了若干个数的点值,在计算多项式乘积时只需要把对应的点值乘起来即可,这也是它最朴素的应用:

void Mul(int *f,int n,int *g,int m){
	int lim=1,l=0;
	while(lim<=n+m)lim<<=1,l++;
	for(int i=0;i<lim;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
	NTT(f,lim,0);NTT(g,lim,0);
	for(int i=0;i<=lim;i++)f[i]=f[i]*g[i]%mod;
	NTT(f,lim,1);
}

这可以让本来平方的多项式乘法变为单 \(\log\)

但是式子题一般不只有乘法,还有除法。除法等价于乘法逆元,相当于对多项式 \(A\),找到一个多项式 \(B\) 使得 \(AB\equiv 1 \pmod {x^{n}}\)。由最朴素的多项式大除法我们可以断定有解。

但是直接算这个东西还是太慢了,考虑迭代。假设我们已经求出了 \(B_k\) 使得 \(AB_k\equiv 1\pmod {x^{2^k}}\),考虑求 \(B_{k+1}\)

我们有 \(AB_k\equiv 1 \pmod {x^{2^k}}\Leftrightarrow AB_k-1\equiv 0\pmod {x^{2^k}}\)。设 \(B_{k+1}=B_k+x^{2^k}C\)\(deg(C)<m\)

于是 \(A(B_k+x^{2^k}C)\equiv 1\pmod {x^{2^{k+1}}}\Leftrightarrow AB_k+x^{2^k}AC\equiv 1\pmod {x^{2^{k+1}}}\)

\(AB_k=1+x^{2^k}D\),有 \(1+x^{2^k}D+x^{2^k}AC\equiv 1\pmod {x^{2^{k+1}}}\Leftrightarrow x^{2^k}AC\equiv -x^{2^k}D\pmod{x^{2^{k+1}}}\Leftrightarrow AC\equiv -D\pmod{x^{2^k}}\)

又有 \(B_k\) 的定义,所以 \(C\equiv -B_k D\pmod {x^{2^k}}\)。又因为 \(AB_k=1+x^{2^k}D\) 所以 \(D=\frac{AB_k-1}{x^{2^k}}\),因此 \(C \equiv -B_k \cdot \frac{A B_k - 1}{x^{2^k}} \pmod{x^{2^k}}\)\(x^{2^k}C\equiv -B_k(AB_k-1)\pmod{x^{2^{k+1}}}\)

所以 \(B_{k+1}=B_k+x^{2^k}C\equiv B_k-B_k(AB_k-1)=2B_k-AB_k^2=B_k(2-AB_k)\pmod{x^{2^{k+1}}}\),然后就可以 NTT 了。

void Inv(int *a,int *b,int sz){
	if(!sz) {
		b[0]=ksm(a[0],mod-2);
		return;
	}
	Inv(a,b,sz/2);
	int lim=1;
	while(lim<=sz*2)lim<<=1;
	for(int i=0;i<=sz;i++)c[i]=a[i];
	for(int i=sz+1;i<=lim;i++)c[i]=0;
	NTT(b,lim,0);NTT(c,lim,0);
	for(int i=0;i<=lim;i++)b[i]=(b[i]*2%mod-b[i]*b[i]%mod*c[i]%mod+mod)%mod;
	NTT(b,lim,1);
	for(int i=sz+1;i<=lim;i++)b[i]=0;
}
posted @ 2026-03-08 17:54  Xuan_tmp  阅读(3)  评论(0)    收藏  举报