多項式 求逆/除法/取模/開根/ln/exp/求冪 (待添加多點求值)


模板直接到最底下

多項式求逆

給定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次項的二次剩餘。
(然而我並不會二次剩餘,而且很多題裏的常數項是真的常數,所以這裏忽略二次剩餘)

補一下二次剩餘這個坑吧
我這輩子應該都學不會那個C開頭的算法了。
但是可以BSGS對原根求出離散對數,把指數除個2,再冪回去。
對於二次剩餘這個做法是正確的,如果指數是奇數不能除2,則這個數是沒有二次剩餘的。

(好像用後面的多項式求冪也能求這個)
當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}

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

多項式求ln

ln(A(x))=[ln(A(x))]dxln(A(x))=\int [ln(A(x))]'dx
=A(x)A(x)dx=\int {A'(x)\over A(x)}dx
求導,求逆,然後積分即可。

多項式exp

牛頓迭代

有函數g()g(),解多項式ff的前n項使g(f)=0g(f)=0
ff有2n項,設前n項使f0f_0
g(f)g(f)f0f_0處泰勒展開

g(f)g(f0)+g(f0)(ff0)+g(f0)(ff0)22!+...mod  x2ng(f)\equiv g(f_0)+g'(f_0)(f-f_0)+{g''(f0)(f-f_0)^2\over 2!}+... \mod x^{2n}

注意到從第三項開始,在mod 2n意義下=0
所以
g(f)g(f0)+g(f0)(ff0)mod  x2ng(f)\equiv g(f_0)+g'(f_0)(f-f_0) \mod x^{2n}

g(f)=0\because g(f)=0

g(f0)+g(f0)(ff0)0mod  x2n\therefore g(f_0)+g'(f_0)(f-f_0)\equiv 0 \mod x^{2n}

ff0g(f0)g(f0)mod  x2nf\equiv f_0-{g(f_0)\over g'(f_0)} \mod x^{2n}

求exp

B(x)exp(A(x))mod  xnB(x)\equiv exp(A(x)) \mod x^n
g(x)=ln(x)Ag(x)=ln(x)-A,那麼目標是g(B)=0g(B)=0
BB0g(B0)g(B0)mod  xnB\equiv B_0-{g(B_0)\over g'(B_0)}\mod x^n

g(B0)=1B0\because g(B_0)'={1\over B_0}

BB0B0(ln(B0)A(x))mod  xn\therefore B\equiv B_0-B_0(ln(B_0)-A(x))\mod x^n

BB0(1+A(x)ln(B0))mod  xnB\equiv B_0(1+A(x)-ln(B_0))\mod x^n
當n=1時直接求(程序中默認常數項=0)
當n>1時倍增

多項式求冪

先ln,再乘上冪數,再exp。

代碼

這個代碼對應的是bzoj3625 CF438E

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(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 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;
}
struct polynomial{
	ll D[N],W[N],A[N],B[N],C[N],E[N],F[N];
	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 mul(ll *a,ll *b,ll *c,int len) //C
	{
		fo(i,0,len-1) A[i]=a[i],B[i]=b[i];
		DFT(A,1,len);DFT(B,1,len);
		fo(i,0,len+len) A[i]=A[i]*B[i]%mo;
		DFT(a,-1,len);
		fo(i,0,len+len) c[i]=A[i];
	}
	void inv(ll *a,ll *b,int deg) ///B
	{
		if(deg==1)
		{
			b[0]=mi(a[0],mo-2);
			b[1]=0;
			return;
		} 
		inv(a,b,deg/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 divide(ll *a,int n,ll *b,int m,ll *c) //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;
		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 mod(ll *a,int n,ll *b,int m,ll *c) //C
	{
		int len=1;
		for(;len<=n;len*=2);
		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 sqrt(ll *a,ll *b,int deg)  //C
	{
		if(deg==1)
		{
			b[0]=1;   //默認常數爲1(不用二次剩餘)
			return;
		}
		sqrt(a,b,deg/2);
		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;
	}
	void ln(ll *a,ll *b,int deg)  //C
	{
		inv(a,C,deg);
		fo(i,0,deg-1) b[i]=1ll*a[i+1]*(i+1)%mo;
		fo(i,deg,deg+deg) C[i]=b[i]=0;
		DFT(b,1,deg);DFT(C,1,deg);
		fo(i,0,deg+deg-1) b[i]=b[i]*C[i]%mo;
		DFT(b,-1,deg);
		fd(i,deg,1) b[i]=b[i-1]*mi(i,mo-2)%mo;
		fo(i,deg,deg+deg) b[i]=0;
		b[0]=0;
	}
	void exp(ll *a,ll *b,int deg)  //E
	{
		if(deg==1)
		{
			b[0]=1;  //默認常數爲0
			b[1]=0;
			return;
		}
		exp(a,b,deg/2);
		ln(b,E,deg);
		fo(i,0,deg-1) E[i]=(a[i]-E[i]+mo)%mo;
		E[0]=(1+E[0]+mo)%mo;
		fo(i,deg,deg+deg) b[i]=E[i]=0;
		DFT(b,1,deg);DFT(E,1,deg);
		fo(i,0,deg+deg-1) b[i]=b[i]*E[i]%mo;
		DFT(b,-1,deg);
		fo(i,deg,deg+deg) b[i]=0;
	}
	void pmi(ll *a,ll *b,ll sig,ll deg) //F
	{
		ln(a,F,deg);
		fo(i,0,deg-1) F[i]=F[i]*sig%mo;
		exp(F,b,deg);
	}
}poly;
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.pmi(a,b,mi(2,mo-2),len);
	b[0]++;
	poly.inv(b,a,len);
	fo(i,1,m) printf("%lld\n",2ll*a[i]%mo);
}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章