多项式总结

某dalao模板

多项式求逆

对于多项式A(x)求B(x)使得 A ( x ) B ( x ) = 1 ( m o d x n ) A(x)B(x)=1(modx^n) A(x)B(x)=1(modxn)
考虑倍增,设 B 0 ( x ) B_0(x) B0(x)使得 A ( x ) B 0 ( x ) = 1 ( m o d x n / 2 ) A(x)B_0(x)=1(mod x^{n/2}) A(x)B0(x)=1(modxn/2)
显然B(x)在 m o d x n / 2 mod x^{n/2} modxn/2的情况下也成立。(由此可见 B 0 ( x ) B_0(x) B0(x) B ( x ) B(x) B(x) n 2 \dfrac{n}{2} 2n项相同)
A ( x ) B 0 ( x ) = A ( x ) B ( x ) ( m o d x n / 2 ) A(x)B_0(x)=A(x)B(x)(modx^{n/2}) A(x)B0(x)=A(x)B(x)(modxn/2) B 0 ( x ) − B ( x ) = 0 ( m o d x n / 2 ) B_0(x)-B(x)=0(modx^{n/2}) B0(x)B(x)=0(modxn/2)
两边平方 B 0 ( x ) 2 + B ( x ) 2 − 2 B 0 ( x ) B ( x ) = 0 ( m o d x n ) B_0(x)^2+B(x)^2-2B_0(x)B(x)=0(modx^n) B0(x)2+B(x)22B0(x)B(x)=0(modxn)
同乘A(x) A ( x ) B 0 ( x ) 2 + B ( x ) − 2 B 0 ( x ) = 0 ( m o d x n ) A(x)B_0(x)^2+B(x)-2B_0(x)=0(mod x^n) A(x)B0(x)2+B(x)2B0(x)=0(modxn) B ( x ) = 2 B 0 ( x ) − A ( x ) B 0 ( x ) 2 ( m o d x n ) B(x)=2B_0(x)-A(x)B_0(x)^2(modx^n) B(x)=2B0(x)A(x)B0(x)2(modxn)
边倍增边维护B数组
注意在算 x n x^n xn是要开到2*n的数组,避免循环卷积的影响。

void polyinv(ll *A,ll *B,int n)//已知A 求B A*B=1 mod x^n
    {
        if(n==1) {B[0]=pow_mod(A[0],mod-2);return;}
        polyinv(A,B,n+1>>1);init(n-1<<1);//虽然不是严格2的幂次,当相当于上界松了,转移正确 
        for(int i=0;i<n;++i) ta[i]=A[i],tb[i]=B[i];
        NTT(ta,1),NTT(tb,1);
        for(int i=0;i<digit;++i) ta[i]=(2*tb[i]%mod-ta[i]*tb[i]%mod*tb[i]%mod+mod)%mod;
        NTT(ta,-1);
        for(int i=0;i<n;++i) B[i]=ta[i],ta[i]=tb[i]=0;
        for(int i=n;i<digit;++i) B[i]=0,ta[i]=tb[i]=0;
    }

多项式除法

已知n次多项式A(x),m次多项式B(x),求C(x),D(x)使得 A ( x ) = B ( x ) C ( x ) + D ( x ) A(x)=B(x)C(x)+D(x) A(x)=B(x)C(x)+D(x)
可以看出C(x)为n-m次,D(x)为m-1次
考虑将x换为 1 x \dfrac{1}{x} x1,等式两边同乘 x n x^n xn
x n A ( 1 x ) = x m B ( 1 x ) x n − m C ( 1 x ) + x n D ( 1 x ) x^nA(\dfrac{1}{x})=x^mB(\dfrac{1}{x})x^{n-m}C(\dfrac{1}{x})+x^nD(\dfrac{1}{x}) xnA(x1)=xmB(x1)xnmC(x1)+xnD(x1)
对于一个n次多项式 x n A ( 1 x ) x^nA(\dfrac{1}{x}) xnA(x1)相当于把系数翻转,记 A ′ ( x ) A&#x27;(x) A(x)为翻转后的多项式
A ′ ( x ) = B ′ ( x ) C ′ ( x ) + x n − m + 1 D ′ ( x ) A&#x27;(x)=B&#x27;(x)C&#x27;(x)+x^{n-m+1}D&#x27;(x) A(x)=B(x)C(x)+xnm+1D(x)
由于 C ( x ) C(x) C(x)是n-m次多项式所以在 m o d x n − m + 1 modx^{n-m+1} modxnm+1的意义下不受影响
C ′ ( x ) = A ′ ( x ) B ′ ( x ) ( m o d x n − m + 1 ) C&#x27;(x)=\dfrac{A&#x27;(x)}{B&#x27;(x)}(modx^{n-m+1}) C(x)=B(x)A(x)(modxnm+1)
多项式求逆,以上。

void polymod(ll *A,ll *B,ll *C,ll *D,int n,int m)//A = B *C +D 
    {
		for(int i=0;i<=n-m;++i) tc[i]=A[n-i];
        for(int i=0;i<=min(n-m,m);++i) td[i]=B[m-i];
        polyinv(td,te,n-m+1);
        init(n-m<<1);
        NTT(tc,1);NTT(te,1);
        for(int i=0;i<digit;++i) tc[i]=tc[i]*te[i]%mod;
        NTT(tc,-1);
        for(int i=0;i<=n-m;++i) tb[i]=C[i]=tc[n-m-i];
        init(n);
        for(int i=0;i<=m;++i) ta[i]=B[i];
        NTT(ta,1);NTT(tb,1);
        for(int i=0;i<digit;++i) ta[i]=ta[i]*tb[i]%mod;
        NTT(ta,-1);
        for(int i=0;i<m;++i) D[i]=(A[i]-ta[i]+mod)%mod;
        for(int i=0;i<digit;++i) ta[i]=tb[i]=tc[i]=td[i]=te[i]=0;
     } 

多项式开根

B ( x ) 2 = A ( x ) ( m o d x n ) B(x)^2=A(x)(modx^n) B(x)2=A(x)(modxn)
考虑倍增 H ( x ) 2 = A ( x ) ( m o d x n / 2 ) H(x)^2=A(x)(modx^{n/2}) H(x)2=A(x)(modxn/2)
移项后平方 ( H ( x ) 2 − A ( x ) ) 2 = 0 ( m o d x n ) (H(x)^2-A(x))^2=0(modx^n) (H(x)2A(x))2=0(modxn) ( H ( x ) 2 + A ( x ) ) 2 = 4 ∗ H ( x ) 2 A ( x ) ( m o d x n ) (H(x)^2+A(x))^2=4*H(x)^2A(x)(modx^n) (H(x)2+A(x))2=4H(x)2A(x)(modxn) A ( x ) = ( H ( x ) 2 + A ( x ) 2 H ( x ) ) 2 ( m o d x n ) A(x)=(\dfrac{H(x)^2+A(x)}{2H(x)})^2(modx^n) A(x)=(2H(x)H(x)2+A(x))2(modxn)
注意这里的 H ( x ) − 1 H(x)^{-1} H(x)1变成了mod(x^n)意义下的。
这里如果 A [ 0 ] = 1 , B [ 0 ] = 1 A[0]=1,B[0]=1 A[0]=1,B[0]=1
否则要求二次剩余

int Sqrt(int x)
     {
    	if(pow_mod(x,mod-1>>1)!=1) return 0;
		ll a=rand();
		while(pow_mod((a*a-x+mod)%mod,mod-1>>1)!=mod-1) a=rand();
		O=(a*a-x+mod)%mod;
		fs ans=(fs){1,0},as=(fs){a,1};
		int b=mod+1>>1;
		while(b)
		{
			if(b&1) ans=ans*as;
			b>>=1;
			as=as*as;
		}
		return ans.x;
	 }
    void polysqrt(ll *A,ll *B,int n)
    {
        if(n==1) 
        {
        	if(A[0]==1) B[0]=1;
        	else B[0]=Sqrt(A[0]);
			return ;
		}
        polysqrt(A,B,n+1>>1);init(n<<1);
        polyinv(B,td,n);
        for(int i=0;i<n;++i) tc[i]=A[i];
        NTT(tc,1),NTT(td,1);
        for(int i=0;i<digit;++i) tc[i]=tc[i]*td[i]%mod;
        NTT(tc,-1);
        ll inv2=(mod+1)/2;
        for(int i=0;i<n;++i) B[i]=(tc[i]+B[i])%mod*inv2%mod,tc[i]=td[i]=0;
        for(int i=n;i<digit;++i) B[i]=0,tc[i]=td[i]=0;
     } 

多项式多点求值

给定一个多项式 A ( x ) A(x) A(x) x 1 − x n x_1-x_n x1xn,求 A ( x ) A(x) A(x)在这n个位置的值。
m i d = n 2 mid=\dfrac{n}{2} mid=2n
A 0 ( x ) = ∑ i = 1 m i d ( x − x i ) A_0(x)=\sum_{i=1}^{mid}(x-x_i) A0(x)=i=1mid(xxi) A 1 ( x ) = ∑ i = m i d + 1 n ( x − x i ) A_1(x)=\sum_{i=mid+1}^{n}(x-x_i) A1(x)=i=mid+1n(xxi)
考虑:
F ( x ) = A 0 ( x ) D 0 ( x ) + R 0 ( x ) F(x)=A_0(x)D_0(x)+R_0(x) F(x)=A0(x)D0(x)+R0(x)
F ( x ) = A 1 ( x ) D 1 ( x ) + R 1 ( x ) F(x)=A_1(x)D_1(x)+R_1(x) F(x)=A1(x)D1(x)+R1(x)
对于 i &lt; = m i d i&lt;=mid i<=mid F ( x i ) = A 0 ( x i ) D 0 ( x i ) + R 0 ( x i ) F(x_i)=A_0(x_i)D_0(x_i)+R_0(x_i) F(xi)=A0(xi)D0(xi)+R0(xi),而 A 0 ( x i ) A_0(x_i) A0(xi)一定存在一项为0,所以 F ( x i ) = R 0 ( x i ) F(x_i)=R_0(x_i) F(xi)=R0(xi),这样我们成功将次数减小一半。
i &gt; m i d i&gt;mid i>mid同理,这样我们成功将次数/2,递归下去。

A ( x ) A(x) A(x)需要先分治求出保存下来。

每一层需要一次多项式取模,复杂度 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n).

void qzinit(int rt,int l,int r)//预处理l~r的多项式(x-xi) 
     {
		 if(l==r)
     	{
     		P[rt]=new ll[2];
		 	P[rt][0]=mod-X[l];
     		P[rt][1]=1;
     		return ;
		 }
		 int mid=l+r>>1;
		 qzinit(rt<<1,l,mid);qzinit(rt<<1|1,mid+1,r);
		 init(r-l+2);
		 for(int i=0;i<=mid-l+1;++i) ta[i]=P[rt<<1][i];
		 for(int i=0;i<=r-mid;++i) tb[i]=P[rt<<1|1][i];
		 P[rt]=new ll[r-l+2];
		 NTT(ta,1);NTT(tb,1);
		 for(int i=0;i<digit;++i) ta[i]=ta[i]*tb[i]%mod;
		 NTT(ta,-1); //ta,tb清零 
		 for(int i=0;i<digit;++i)
		 {
		 	if(i<=r-l+1) P[rt][i]=ta[i];
		 	ta[i]=tb[i]=0;
		 }
	 }
	 void polyqz(int rt,int l,int r,int dep)
	 {
	 	if(l==r)
	 	{
	 		as[l]=T[dep][0];
	 		return ;
		 }
		 int mid=l+r>>1;
		 polymod(T[dep],P[rt<<1],ever,T[dep+1],r-l,mid-l+1);
		 polyqz(rt<<1,l,mid,dep+1);
		 polymod(T[dep],P[rt<<1|1],ever,T[dep+1],r-l,r-mid);
		 polyqz(rt<<1|1,mid+1,r,dep+1); 
	 }

多项式求LN

注:只有常数项为1的多项式可以取ln.

l n F = ∫ F F − 1 lnF=\int_{}{}FF^{-1} lnF=FF1

void direv(ll *A,int n)
     {
     	for(int i=1;i<=n;++i) A[i-1]=A[i]*i%mod;A[n]=0;
     }
     void inter(ll *A,int n)
     {
     	for(int i=n;i>=1;--i) A[i]=A[i-1]*pow_mod(i,mod-2)%mod;A[0]=0;
     }
     void polyln(ll *A,ll *B,int n) //mod x^n lnA=B
     {
     	polyinv(A,B,n);direv(A,n-1);
     	init(n<<1);
     	for(int i=0;i<n;++i) tt[i]=A[i]; 
     	NTT(tt,1),NTT(B,1);
     	for(int i=0;i<digit;++i) B[i]=B[i]*tt[i]%mod;
     	NTT(B,-1);
     	for(int i=0;i<digit;++i) tt[i]=0;
     	inter(B,n-1);
     }

多项式牛顿迭代

参考资料
已知 G ( x ) G(x) G(x),求F(x)使得 G ( F ( x ) ) = 0 G(F(x))=0 G(F(x))=0 m o d x n mod x^n modxn
考虑倍增
F ( x ) = F 0 ( x ) − G ( F 0 ( x ) ) G ′ ( F 0 ( x ) ) F(x)=F_{0}(x)-\dfrac{G(F_{0}(x))}{G&#x27;(F_{0}(x))} F(x)=F0(x)G(F0(x))G(F0(x))
可以利用这个式子推导很多东西。

多项式exp

B ( x ) = e A ( x ) B(x)=e^{A(x)} B(x)=eA(x) m o d x n mod x^n modxn,保证A(0)=0。
l n F ( x ) − A ( x ) = 0 lnF(x)-A(x)=0 lnF(x)A(x)=0
l n F ( x ) − A ( x ) = G ( F ( x ) ) lnF(x)-A(x)=G(F(x)) lnF(x)A(x)=G(F(x))
两边求导
G ′ ( F ( x ) ) = 1 F ( x ) G&#x27;(F(x))=\dfrac{1}{F(x)} G(F(x))=F(x)1
带入牛顿迭代的式子
F ( x ) = F 0 ( x ) ( 1 − l n F 0 ( x ) + A ( x ) ) F(x)=F_{0}(x)(1-lnF_{0}(x)+A(x)) F(x)=F0(x)(1lnF0(x)+A(x))
倍增即可

void polyexp(ll *A,ll *B,int n)
	 {
	 	if(n==1) 
	 	{
	 		B[0]=1;
	 		return ;
		 }
		 polyexp(A,B,n+1>>1);init(n-1<<1);
		 for(int i=0;i<n;++i) tc[i]=td[i]=B[i];
		 polyln(td,te,n);
		 for(int i=0;i<n;++i) td[i]=(A[i]-te[i]+mod)%mod;
		 for(int i=n;i<digit;++i) td[i]=tc[i]=0; 
		 td[0]++;
		 NTT(tc,1);NTT(td,1);
		 for(int i=0;i<digit;++i) tc[i]=tc[i]*td[i]%mod;
		 NTT(tc,-1);
		 for(int i=0;i<digit;++i)
		 {
		 	if(i<n) B[i]=tc[i];
		 	tc[i]=td[i]=te[i]=0;
		 }
	 }

多项式幂函数

G ( x ) = A ( x ) k G(x)=A(x)^k G(x)=A(x)k

如果A(0)=1

两边取ln l n G ( x ) = k l n A ( x ) lnG(x)=klnA(x) lnG(x)=klnA(x)
再两边变成e的指数 G ( x ) = e x p ( k l n A ( x ) ) G(x)=exp(klnA(x)) G(x)=exp(klnA(x))

否则

设最低项为 a t x t a_tx^t atxt,那我把多项式拆成两部分以便于上述操作
G ( x ) = a t k x k t e x p ( k l n A ( x ) a t x t ) G(x)=a_t^kx^{kt}exp(kln\dfrac{A(x)}{a_tx^t}) G(x)=atkxktexp(klnatxtA(x))

void polypow(ll *A,ll *B,int n,ll k)
     {
     	if(A[0]==1)//判常数项是否为1 
     	{
     		polyln(A,C,n);
       		for(int i=0;i<n;++i) C[i]=C[i]*k%mod;
       		polyexp(C,B,n);
       		for(int i=0;i<n;++i) C[i]=0;
		 }
		 else
		 {
		 	int pos=0;
		 	for(;!A[pos];++pos);
		 	int tmp=pow_mod(A[pos],mod-2);
		 	for(int i=pos;i<n;++i) D[i-pos]=A[i]*tmp%mod; 
		 	polyln(D,C,n);
       		for(int i=0;i<n;++i) C[i]=C[i]*k%mod;
       		polyexp(C,B,n);
       		tmp=pow_mod(A[pos],k);
       		if(pos*k<n) for(int i=n-pos*k-1;i>=0;--i) B[i+pos*k]=B[i]*tmp%mod;
       		for(int i=0;i<n&&i<pos*k;++i) B[i]=0;
       		for(int i=0;i<n;++i) C[i]=D[i]=0;
		 }
     }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值