多項式 求逆/除法/取模/開根 (待添加 指數函數/對數函數/多點求值)

模板直接到最底下

多項式求逆

給定A(x)A(x)B(x)=A1(x)(modxn)B(x)=A^{-1}(x)(mod x^n)
使用倍增構造。
若n=1,則直接求0次項的乘法逆元。
若n>1
B(x)B(x)滿足
A(x)B(x)1mod  xn/2A(x)B(x)\equiv 1 \mod x^{n/2}

A(x)B(x)10mod  xn/2A(x)B(x)-1\equiv 0 \mod x^{n/2}

(A(x)B(x)1)20mod  xn(A(x)B(x)-1)^2\equiv 0 \mod x^{n}

A2(x)B2(x)2A(x)B(x)+10mod  xnA^2(x)B^2(x)-2A(x)B(x)+1\equiv 0 \mod x^{n}

A(x)(2B(x)A(x)B2(x))1mod  xnA(x)(2B(x)-A(x)B^2(x))\equiv 1 \mod x^{n}

2B(x)A(x)B2(x)A1(x)mod  xn2B(x)-A(x)B^2(x)\equiv A^{-1}(x) \mod x^{n}

遞歸即可,複雜度O(nlog(n))O(nlog(n))

多項式除法

已知A(x),B(x)A(x),B(x),它們的次數分別爲n,m(n>m)n,m(n>m)

A(x)=B(x)C(x)+D(x)A(x)=B(x)C(x)+D(x)

C(x)C(x)是除法,D(x)D(x)是取模,其中C(x)C(x)的係數不大於nmn-mD(x)D(x)的係數小於mm

首先可以發現A(x)=xnA(1x)A'(x)=x^nA({1\over x})就是將A的係數翻轉過來。

同乘xnx^n
那麼
xnA(1x)=xmB(1x)xnmC(1x)+xnm+1xm1D(1x)x^nA({1\over x})=x^mB({1\over x})x^{n-m}C({1\over x})+x^{n-m+1}x^{m-1}D({1\over x})

將這個東西mod  xnm+1\mod x^{n-m+1},可以發現對C(x)C(x)的係數不會有影響。
於是
A(x)B(x)C(x)mod  xnm+1A'(x)\equiv B'(x)C'(x) \mod x^{n-m+1}

C(x)A(x)B1(x)mod  xnm+1C'(x)\equiv A'(x)B'^{-1}(x) \mod x^{n-m+1}

於是多項式求逆,然後乘起來就沒了。

多項式取模

A(x)=B(x)C(x)+D(x)A(x)=B(x)C(x)+D(x)

先除,再乘,再減,就沒了。

多項式開方

給定A(x)A(x)B2(x)=A(x)(modxn)B^2(x)=A(x)(mod x^n)
使用倍增構造。
當n=1時,相當於求0次項的二次剩餘。
(然而我並不會二次剩餘,而且很多題裏的常數項是真的常數,所以這裏忽略二次剩餘)
當n>1時,
B(x),G(x)B(x),G(x)滿足
B2(x)A(x)mod  xn/2,G2(x)A(x)mod  xnB^2(x)\equiv A(x) \mod x^{n/2},G^2(x)\equiv A(x) \mod x^{n}

G2(x)B2(x)0mod  xn/2G^2(x)-B^2(x)\equiv 0 \mod x^{n/2}

兩邊平方
G4(x)+B4(x)2G2(x)B2(x)0mod  xnG^4(x)+B^4(x)-2G^2(x)B^2(x)\equiv 0 \mod x^{n}

(G2(x)+B2(x))24G2(x)B2(x)mod  xn/2(G^2(x)+B^2(x))^2\equiv 4G^2(x)B^2(x) \mod x^{n/2}

G2(x)+B2(x)2G(x)B(x)mod  xn/2G^2(x)+B^2(x)\equiv 2G(x)B(x) \mod x^{n/2}

因爲G2(x)A(x)mod  xnG^2(x)\equiv A(x) \mod x^{n}
A(x)+B2(x)2G(x)B(x)mod  xn/2A(x)+B^2(x)\equiv 2G(x)B(x) \mod x^{n/2}

A(x)2B(x)+B(x)2G(x)mod  xn/2{A(x)\over 2B(x)}+{B(x)\over 2}\equiv G(x) \mod x^{n/2}

求逆然後乘一乘,加一加就行了。

Code

這個代碼對應的是bzoj3625 CF438E

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 3201000
#define ll long long
#define mo 998244353
using namespace std;
int n,m;
ll D[N],W[N],A[N],B[N],C[N],E[N],len,a[N],b[N],c[N];
ll mi(ll a,ll b)
{
	a%=mo;ll jy=1;
	for(;b;b/=2,a=a*a%mo) if(b%2==1) jy=jy*a%mo;
	return jy;
}
void DFT(ll *a,int sig,int deg)
{
	int len,lg;
	for(len=1,lg=0;len<=deg;len*=2,lg++);
	W[0]=1;W[1]=mi(3,(mo-1)/len);fo(i,2,len) W[i]=W[i-1]*W[1]%mo;
	fo(i,0,len-1)
	{
		int p=0;
		for(int j=0,tp=i;j<lg;j++,tp/=2) p=(p<<1)+(tp%2);
		D[p]=a[i];
	}
	for(int m=2;m<=len;m*=2)
	{
		int half=m/2,tmp=len/m;
		for(int j=0;j<len;j+=m)
		{
			fo(i,j,j+half-1)
			{
				ll u=D[i],v=D[i+half]*((sig==1)?W[(i-j)*tmp]:W[len-(i-j)*tmp])%mo;
				D[i]=(u+v)%mo;
				D[i+half]=(u-v+mo)%mo;
			}
		}
	}
	if(sig==-1)
	{
		ll inv=mi(len,mo-2);
		fo(i,0,len-1) D[i]=D[i]*inv%mo;
	}
	fo(i,0,len-1) a[i]=D[i];
}
void poly_inv(ll *a,ll *b,int deg)
{
	if(deg==1)
	{
		b[0]=mi(a[0],mo-2);
		b[1]=0;
		return;
	} 
	poly_inv(a,b,(deg+1)/2);
	fo(i,0,deg-1) A[i]=a[i],B[i]=b[i];
	fo(i,deg,deg+deg-1) A[i]=B[i]=0;
	DFT(A,1,deg);DFT(B,1,deg);
	fo(i,0,deg+deg-1) A[i]=(A[i]*B[i]%mo*B[i]%mo)%mo;
	DFT(A,-1,deg);
	fo(i,0,deg-1) b[i]=(b[i]*2ll-A[i]+mo)%mo;
	fo(i,deg,deg+deg) b[i]=0;
}
void poly_divide(ll *a,int n,ll *b,int m,ll *c)
{
	int len=1;
	for(;len<n-m+1;len*=2);
	fo(i,0,m-1) c[i]=b[m-i-1],C[i]=0;
	fo(i,min(m,n-m+1),len+len) c[i]=C[i]=0;
	poly_inv(c,C,len);
	fo(i,0,n-1) A[i]=a[n-i-1];
	fo(i,n-m+1,len+len) A[i]=C[i]=0;
	DFT(A,1,len);DFT(C,1,len);
	fo(i,0,len+len) A[i]=A[i]*C[i]%mo;
	DFT(A,-1,len);
	fo(i,0,n-m) c[i]=A[n-m-i];	
}
void poly_mod(ll *a,int n,ll *b,int m,ll *c)
{
	int len=1;
	for(;len<=n;len*=2);
	poly_divide(a,n,b,m,c);
	fo(i,n-m+1,len+len) c[i]=0;
	fo(i,0,m-1) A[i]=b[i];
	fo(i,m,len+len) A[i]=0;
	DFT(A,1,len);DFT(c,1,len);
	fo(i,0,len+len) A[i]=A[i]*c[i]%mo;
	DFT(A,-1,len);
	fo(i,0,m-2) c[i]=(a[i]-A[i]+mo)%mo;
}
void poly_sqrt(ll *a,ll *b,int deg)
{
	if(deg==1)
	{
		b[0]=1;   //默認常數爲1(不用二次剩餘)
		return;
	}
	poly_sqrt(a,b,deg/2);
	poly_inv(b,C,deg);
	fo(i,0,deg-1) A[i]=a[i];
	fo(i,deg,deg+deg) A[i]=0,C[i]=0;
	DFT(A,1,deg);DFT(C,1,deg);
	fo(i,0,deg+deg-1) A[i]=A[i]*C[i]%mo;
	DFT(A,-1,deg);
	ll ny2=mi(2,mo-2);
	fo(i,0,deg-1) b[i]=(b[i]*ny2%mo+A[i]*ny2%mo)%mo;
}
int main()
{
	int mx=0;
	scanf("%d%d",&n,&m);
	fo(i,1,n)
	{
		int x;scanf("%d",&x);
		a[x]=mo-4;
		mx+=x;
	}
	for(len=1;len<=m;len*=2);
	a[0]++;
	poly_sqrt(a,b,len);
	b[0]++;
	poly_inv(b,a,len);
	fo(i,1,m) printf("%lld\n",2ll*a[i]%mo);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章