1. 程式人生 > 其它 >[Vue] #常見開發場景 #條件渲染#手動掛載 #元件方法的值驅動執行

[Vue] #常見開發場景 #條件渲染#手動掛載 #元件方法的值驅動執行

多項式求逆元

已知一度數為n的多項式\(A(x)\)

\[A(x)B(x)\equiv1\pmod {x^n} \]

\(B(x)\)即為\(A(x)\)的逆元。

多項式的除法、\(\exp\)\(\ln\)都是基於多項式求逆的。

通常用倍增法處理多項式求逆問題。

開始推式子……

\[\begin{aligned} &AB'\equiv1\pmod {x^{\lceil\frac n 2\rceil}}\\ &A(B-B’)\equiv 0 \pmod {x^{\lceil\frac n 2\rceil}}\\ &B-B’\equiv 0 \pmod {x^{\lceil\frac n 2\rceil}}\\ &(B-B’)^2\equiv 0 \pmod {x^n}\\ &B^2+B'^2-2BB'\equiv 0 \pmod {x^n}\\ &A(B^2+B'^2-2BB')\equiv 0 \pmod {x^n}\\ &B-2B'+AB'^2\equiv 0 \pmod {x^n}\\ &B\equiv 2B'-AB'^2\pmod {x^n}\\ &B\equiv B'(2-AB')\pmod {x^n}\\ \end{aligned} \]

這樣我們可以從\(x^n\)

遞迴到\(x^0\)

使用NTT加速運算,複雜度\(O(n \log n)\)

ll qp(ll d,ll c)
{
	ll res=1;
	while(c)
	{
		if(c&1) res=d*res%mod;
		d=d*d%mod,c>>=1;
	}
	return res;
} 
void ntt(ll *a,int type)
{
	for(int i=0;i<lim;i++) 
		if(i<rev[i]) 
			swap(a[i],a[rev[i]]);
	for(int mid=1;mid<lim;mid<<=1)
	{
		ll wn=qp(type?g:gi,(mod-1)/(mid<<1));
		for(int i=0;i<lim;i+=(mid<<1))
		{
			ll w=1;
			for(int j=0;j<mid;j++,w=w*wn%mod)
			{
				ll x=a[i+j],y=w*a[i+j+mid]%mod;
				a[i+j]=(x+y)%mod;
				a[i+j+mid]=(x-y+mod)%mod;
			}
		}
	}
	if(!type)
	{
		ll inv=qp(lim,mod-2);
		for(int i=0;i<lim;i++)
			a[i]=(a[i]*inv)%mod;
	}
}
void qn(ll deg,ll *a,ll *b)
{
	if(deg==1)
	{
		b[0]=qp(a[0],mod-2);
		return;
	}
	qn((deg+1)/2,a,b);
	bit=0,lim=1;
	for(;lim<deg*2;lim*=2)
		bit++; 
	for(int i=1;i<lim;i++) 
		rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
	for(int i=0;i<deg;i++)
		c[i]=a[i];
	for(int i=deg;i<lim;i++)
		c[i]=0;
	ntt(c,1),ntt(b,1);
	for(int i=0;i<lim;i++)
		b[i]=(2-c[i]*b[i]%mod+mod)%mod*b[i]%mod;	
	ntt(b,0);
	for(int i=deg;i<lim;i++)
		b[i]=0;
}