我是靠谱客的博主 舒适水蜜桃,最近开发中收集的这篇文章主要介绍多项式多项式,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

多项式

前置知识

多项式的度:

多项式 f ( x ) f(x) f(x)的最高次项的次数为该多项式的度,记为 d e g   f deg f deg f

多项式的逆元:

对于多项式 f ( x ) f(x) f(x),若存在 g ( x ) g(x) g(x)满足:
f ( x ) g ( x ) ≡ 1 ( m o d x n ) f(x)g(x)equiv 1pmod{x^n} f(x)g(x)1(modxn)
d e g   g ≤ d e g   f deg gle deg f deg gdeg f
则称 g ( x ) g(x) g(x) f ( x ) f(x) f(x)在模 x n x^n xn意义下的逆元,记作 f − 1 ( x ) f^{-1}(x) f1(x)

多项式的余数和商:

对于多项式 f ( x ) , g ( x ) f(x),g(x) f(x),g(x),存在唯一的 Q ( x ) , R ( x ) Q(x),R(x) Q(x),R(x)满足:
f ( x ) = Q ( x ) g ( x ) + R ( x ) f(x)=Q(x)g(x)+R(x) f(x)=Q(x)g(x)+R(x)
d e g   Q = d e g   f − d e g   g deg Q=deg f-deg g deg Q=deg fdeg g
d e g   R < d e g   g deg R< deg g deg R<deg g
f ( x ) ≡ R ( x ) ( m o d g ( x ) ) f(x)equiv R(x)pmod {g(x)} f(x)R(x)(modg(x))
Q ( x ) Q(x) Q(x)为商, R ( x ) R(x) R(x)为余数

多项式的多点求值和插值

多点求值:给出一个多项式 f ( x ) f(x) f(x) n n n个点 x 1 , x 2 , … , x n x_1,x_2,…,x_n x1,x2,,xn,求 f ( x 1 ) , f ( x 2 ) , … , f ( x n ) f(x_1),f(x_2),…,f(x_n) f(x1),f(x2),,f(xn)
插值:给出 n + 1 n+1 n+1个点 ( x 0 , y 0 ) , ( x 1 , y 1 ) , … , ( x n , y n ) (x_0,y_0),(x_1,y_1),…,(x_n,y_n) (x0,y0),(x1,y1),,(xn,yn)
求一个 n n n次多项式 f ( x ) f(x) f(x)使得这 n + 1 n+1 n+1个点都在 f ( x ) f(x) f(x)上。

拉格朗日插值

给出 n n n个点 P i ( x i , y i ) P_i(x_i,y_i) Pi(xi,yi),将过这 n n n个点的最多 n − 1 n-1 n1次多项式记为 f ( x ) f(x) f(x),求 f ( k ) f(k) f(k)的值。
由这 n n n个点可以构建 n n n个简单多项式 g i ( x ) g_i(x) gi(x),使得 g i ( x i ) = y i & & g i ( x j ) = 0 , j ≠ i g_i(x_i)=y_i&& g_i(x_j)=0,jne i gi(xi)=yi&&gi(xj)=0,j=i
那么 f ( x ) = ∑ i = 1 n g i ( x ) f(x)=sum_{i=1}^ng_i(x) f(x)=i=1ngi(x)
很明显, g i ( x ) = y i × ( ∏ j ≠ i x − x j x i − x j ) g_i(x)=y_itimes(prodlimits_{jne i}frac{x-x_j}{x_i-x_j}) gi(x)=yi×(j=ixixjxxj)
所以 f ( x ) = ∑ i = 1 n y i × ( ∏ j ≠ i x − x j x i − x j ) f(x)=sumlimits_{i=1}^{n}y_itimes(prodlimits_{jne i}frac{x-x_j}{x_i-x_j}) f(x)=i=1nyi×(j=ixixjxxj)
代入 k k k, f ( k ) = ∑ i = 1 n y i × ( ∏ j ≠ i k − x j x i − x j ) f(k)=sumlimits_{i=1}^{n}y_itimes(prodlimits_{jne i}frac{k-x_j}{x_i-x_j}) f(k)=i=1nyi×(j=ixixjkxj)

快速傅里叶变换(FFT)

系数表示法

f ( x ) = a 2 x 2 + a 1 x + a 0 ⇔ f ( x ) = { a 2 , a 1 , a 0 } f(x)=a_2x^2+a_1x+a_0Leftrightarrow f(x)={a_2,a_1,a_0} f(x)=a2x2+a1x+a0f(x)={a2,a1,a0}

点值表示法

从多项式 f ( x ) f(x) f(x)上取 n + 1 n+1 n+1个有效点,来唯一表示这个函数。
如下:
f 1 ( x ) = y 1 = a 0 + a 1 x 1 + a 2 x 1 2 + … + a n x 1 n f_1(x)=y_1=a_0+a_1x_1+a_2x_1^2+…+a_nx_1^n f1(x)=y1=a0+a1x1+a2x12++anx1n
f 2 ( x ) = y 2 = a 0 + a 1 x 2 + a 2 x 2 2 + … + a n x 2 n f_2(x)=y_2=a_0+a_1x_2+a_2x_2^2+…+a_nx_2^n f2(x)=y2=a0+a1x2+a2x22++anx2n
f 3 ( x ) = y 3 = a 0 + a 1 x 3 + a 2 x 3 2 + … + a n x 3 n f_3(x)=y_3=a_0+a_1x_3+a_2x_3^2+…+a_nx_3^n f3(x)=y3=a0+a1x3+a2x32++anx3n
⋮ vdots
f n + 1 ( x ) = y 1 = a 0 + a 1 x n + 1 + a 2 x n + 1 2 + … + a n x n + 1 n f_{n+1}(x)=y_1=a_0+a_1x_{n+1}+a_2x_{n+1}^2+…+a_nx_{n+1}^n fn+1(x)=y1=a0+a1xn+1+a2xn+12++anxn+1n

DFT

多项式由系数表示法转为点值法的过程

IDFT

多项式的点值表示法转化为系数表示法的过程

FFT

通过取某些特殊的 x x x的点值来加速DFT和IDFT的过程

单位复根

两个点值表示的多项式乘积复杂度为 O ( n ) O(n) O(n),如下:
假设我们DFT过程对于两个多项式选取的 x x x序列相同,那么可以得到:
f ( x ) = ( x 0 , f ( x 0 ) ) , ( x 1 , f ( x 1 ) ) , ( x 2 , f ( x 2 ) ) , … , ( x n , f ( x n ) ) f(x)=(x_0,f(x_0)),(x_1,f(x_1)),(x_2,f(x_2)),…,(x_n,f(x_n)) f(x)=(x0,f(x0)),(x1,f(x1)),(x2,f(x2)),,(xn,f(xn))
g ( x ) = ( x 0 , g ( x 0 ) ) , ( x 1 , g ( x 1 ) ) , ( x 2 , g ( x 2 ) ) , … , ( x n , g ( x n ) ) g(x)=(x_0,g(x_0)),(x_1,g(x_1)),(x_2,g(x_2)),…,(x_n,g(x_n)) g(x)=(x0,g(x0)),(x1,g(x1)),(x2,g(x2)),,(xn,g(xn))
如果设 F ( x ) = f ( x ) × g ( x ) F(x)=f(x)times g(x) F(x)=f(x)×g(x):
F ( x ) F(x) F(x)的点值表达式为: F ( x ) = ( x 0 , f ( x 0 ) g ( x 0 ) ) , ( x 1 , f ( x 1 ) g ( x 1 ) ) , … , ( x n , f ( x n ) g ( x n ) ) F(x)=(x_0,f(x_0)g(x_0)),(x_1,f(x_1)g(x_1)),…,(x_n,f(x_n)g(x_n)) F(x)=(x0,f(x0)g(x0)),(x1,f(x1)g(x1)),,(xn,f(xn)g(xn))
如果能快速得到 F ( x ) F(x) F(x)的系数表达式,则这个问题就完美解决了。
我们可以观察到,为了计算 F ( x ) F(x) F(x),就需要计算很多 x i x^i xi,为了能快速得到 x i x^i xi,引入 ω n k , 0 ≤ k < n omega_n^k,0le k<n ωnk,0k<n,表示复数域上单位圆被 n n n等分后的第 k k k个,从0开始。由复数的性质可知 ( ω n k ) n ∗ i = 1 (omega_n^k)^{n*i}=1 (ωnk)ni=1, ω n k = ( ω n 1 ) k omega_n^k=(omega_n^1)^k ωnk=(ωn1)k.

FFT的流程

DFT

例子:
f ( x ) = a 0 + a 1 x + a 2 x 2 + … + a 7 x 7 f(x)=a_0+a_1x+a_2x^2+…+a_7x^7 f(x)=a0+a1x+a2x2++a7x7
f ( x ) = ( a 0 + a 2 x 2 + a 4 x 4 + a 6 x 6 ) + x ( a 1 + a 3 x 2 + a 5 x 4 + a 7 x 6 ) f(x)=(a_0+a_2x^2+a_4x^4+a_6x^6)+x(a_1+a_3x^2+a_5x^4+a_7x^6) f(x)=(a0+a2x2+a4x4+a6x6)+x(a1+a3x2+a5x4+a7x6)
令: G ( x ) = a 0 + a 2 x + a 4 x 2 + a 6 x 3 G(x)=a_0+a_2x+a_4x^2+a_6x^3 G(x)=a0+a2x+a4x2+a6x3
H ( x ) = a 1 + a 3 x + a 5 x 2 + a 7 x 3 H(x)=a_1+a_3x+a_5x^2+a_7x^3 H(x)=a1+a3x+a5x2+a7x3
F ( x ) = G ( x 2 ) + x H ( x 2 ) F(x)=G(x^2)+xH(x^2) F(x)=G(x2)+xH(x2)
即有: D F T ( f ( ω n k ) ) = D F T ( G ( ( ω n k ) 2 ) ) + ω n k D F T ( H ( ( ω n k ) 2 ) ) DFT(f(omega_n^k))=DFT(G((omega_n^k)^2))+omega_n^kDFT(H((omega_n^k)^2)) DFT(f(ωnk))=DFT(G((ωnk)2))+ωnkDFT(H((ωnk)2))
这个函数能处理的多项式长度只能是 2 m 2^m 2m,高次系数补0即可。这个代码还需要继续优化。
设初始序列为 { x 0 , x 1 , x 2 , x 3 , x 4 , x 5 , x 6 , x 7 } {x_0,x_1,x_2,x_3,x_4,x_5,x_6,x_7} {x0,x1,x2,x3,x4,x5,x6,x7}
一次二分后为 { x 0 , x 2 , x 4 , x 6 } , { x 1 , x 3 , x 5 , x 7 } {x_0,x_2,x_4,x_6},{x_1,x_3,x_5,x_7} {x0,x2,x4,x6},{x1,x3,x5,x7}
二次二分后为 { x 0 , x 4 } , { x 2 , x 6 } , { x 1 , x 5 } , { x 3 , x 7 } {x_0,x_4},{x_2,x_6},{x_1,x_5},{x_3,x_7} {x0,x4},{x2,x6},{x1,x5},{x3,x7}
三次二分后为 { x 0 } , { x 4 } , { x 2 } , { x 6 } , { x 1 } , { x 5 } , { x 3 } , { x 7 } {x_0},{x_4},{x_2},{x_6},{x_1},{x_5},{x_3},{x_7} {x0},{x4},{x2},{x6},{x1},{x5},{x3},{x7}
其实就是原来的那个序列,每个数用二进制表示,然后把二进制翻转对称一下,就是最终那个位置的下标。

IDFT

由于写成矩阵形式后,
[ y [ 0 ] y [ 1 ] y [ 2 ] y [ 3 ] … y [ n − 1 ] ] = = = = = [ 1 1 1 1 … 1 1 ω n 1 ω n 2 ω n 3 … ω n n − 1 1 ω n 2 ω n 4 ω n 6 … ω n 2 ( n − 1 ) 1 ω n 3 ω n 6 ω n 9 … ω n 3 ( n − 1 ) … … … … … … 1 ω n n − 1 ω n 2 ( n − 1 ) ω n 3 ( n − 1 ) … ω n ( n − 1 ) 2 ] [ a [ 0 ] a [ 1 ] a [ 2 ] a [ 3 ] … a [ n − 1 ] ] begin{bmatrix}y[0] \ y[1] \ y[2] \ y[3] \ dots \ y[n-1] end{bmatrix} begin{matrix}= \ = \ = \ = \ \ = end{matrix} begin{bmatrix}1 & 1 & 1 & 1 & dots & 1 \ 1 & omega_n^1 & omega_n^2 & omega_n^3 & dots & omega_n^{n-1} \ 1 & omega_n^2 & omega_n^4 & omega_n^6 & dots & omega_n^{2(n-1)} \ 1 & omega_n^3 & omega_n^6 & omega_n^9 & dots & omega_n^{3(n-1)} \ dots & dots & dots & dots & dots & dots \ 1 & omega_n^{n-1} & omega_n^{2(n-1)} & omega_n^{3(n-1)} & dots & omega_n^{(n-1)^2} end{bmatrix} begin{bmatrix} a[0] \ a[1] \ a[2] \ a[3] \ dots \ a[n-1] end{bmatrix} y[0]y[1]y[2]y[3]y[n1]=====111111ωn1ωn2ωn3ωnn11ωn2ωn4ωn6ωn2(n1)1ωn3ωn6ωn9ωn3(n1)1ωnn1ωn2(n1)ωn3(n1)ωn(n1)2a[0]a[1]a[2]a[3]a[n1]
这个矩阵是范德蒙德矩阵,其逆矩阵是每一项求倒数后除以 n n n,然后发现 ω n i omega_n^i ωni倒数是就是 ω n − i omega_n^{-i} ωni
所以把fft多加一个参数, o n = = 1 on==1 on==1时是FFT, o n = = − 1 on==-1 on==1时是IFFT,只要构造单位复根时取 ω n = cos ⁡ ( o n ∗ 2 π / n ) + i sin ⁡ ( o n ∗ 2 π / n ) omega_n=cos(on*2pi/n)+isin(on*2pi/n) ωn=cos(on2π/n)+isin(on2π/n),就完成了FFT和IFFT的构造。

///FFT
///高精度乘法
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const double PI = acos(-1.0);
//复数
struct Complex{
double x,y;
Complex(double _x = 0.0,double _y = 0.0){
x=_x;y=_y;
}
Complex operator-(const Complex &b) const {
return Complex(x-b.x,y-b.y);
}
Complex operator+(const Complex &b) const {
return Complex(x+b.x,y+b.y);
}
Complex operator*(const Complex &b) const {
return Complex(x*b.x-y*b.y,x*b.y+y*b.x);
}
};
/*
*进行FFT和IFFT前的反置变换
*位置i和i的二进制翻转后的位置互换
*len必须为2的幂次
*/
void change(Complex y[],int len){
int i,j,k;
for(int i=1,j=len/2;i<len-1;i++){
if(i<j)swap(y[i],y[j]);
k=len/2;
while(j>=k){
j=j-k;
k=k/2;
}
if(j<k) j+=k;
}
}
/*
*FFT
*len必须是2的幂次
*on==1时是DFT,on==-1时是IDFT
*/
void fft(Complex y[],int len ,int on){
change(y,len);//翻转系数
//倍增法
for(int h=2;h<=len;h<<=1){
//取单位复根
Complex wn(cos(2*PI/h),sin(on*2*PI/h));
for(int j=0;j<len;j+=h){
Complex w(1,0);
for(int k=j;k<j+h/2;k++){
Complex u=y[k];
Complex t=w*y[k+h/2];
y[k]=u+t;
y[k+h/2]=u-t;
w=w*wn;
}
}
}
//IFFT时,需要将结果/len
if(on==-1){
for(int i=0;i<len;i++){
y[i].x/=len;
}
}
}
const int maxn = 200020;
Complex x1[maxn],x2[maxn];
char str1[maxn/2],str2[maxn/2];
int sum[maxn];
int main(){
while(scanf("%s%s",str1,str2)==2){
int len1=strlen(str1);
int len2=strlen(str2);
int len=1;
while(len<len1*2||len<len2*2)len<<=1;
for(int i=0;i<len1;i++)
x1[i]=Complex(str1[len1-1-i]-'0',0);
for(int i=len1;i<len;i++)
x1[i]=Complex(0,0);
for(int i=0;i<len2;i++)
x2[i]=Complex(str2[len2-1-i]-'0',0);
for(int i=len2;i<len;i++)
x2[i]=Complex(0,0);
fft(x1,len,1);
fft(x2,len,1);
//转化为点值表示法后计算乘积
for(int i=0;i<len;i++)
x1[i]=x1[i]*x2[i];
//IDFT
fft(x1,len,-1);
for(int i=0;i<len;i++)
sum[i]=int(x1[i].x + 0.5);
for(int i=0;i<len;i++){
sum[i+1]+=sum[i]/10;
sum[i]%=10;
}
len=len1+len2-1;
while(sum[len]==0&&len>0)len--;
for(int i=len;i>=0;i--)
printf("%c",sum[i]+'0');
printf("n");
}
return 0;
}

快速数论变换(NTT)

生成子群

群:一个满足封闭性、满足结合律、有单位元、有逆元的二元运算的代数结构。
子群:群 ( S , ⊕ ) , S ( S ′ , ⊕ ) (S,oplus),S(S',oplus) (S,),S(S,),满足 S ′ ⊂ S S' subset S SS,则 ( S ′ , ⊕ ) (S',oplus) (S,) ( S , ⊕ ) (S,oplus) (S,)的子群
拉格朗日定理: ∣ S ′ ∣ |S'| S ∣ S ∣ |S| S的因子
生成子群: a ∈ S ain S aS的生成子群 < a > = { a ( k ) , k ≥ 1 } left<aright>={a^{(k)},kge 1} a={a(k),k1} a a a < a > left<aright> a的生成元
阶:群 S S S a a a的阶是满足 a r = e a^r=e ar=e,( e e e是单位元),的最小的 r r r,记为 o r d ( a ) = ∣ < a > ∣ ord(a)=|left<aright>| ord(a)=a
考虑群 Z n × = { [ a ] , n ∈ Z n : g c d ( a , n ) = 1 } , ∣ Z n × ∣ = φ ( n ) Z_n^{times}={[a],nin Z_n:gcd(a,n)=1},|Z_n^{times}|=varphi(n) Zn×={[a],nZn:gcd(a,n)=1},Zn×=φ(n)

原根

g g g满足 o r d n ( g ) = ∣ Z n × ∣ = φ ( n ) ord_n(g)=|Z_n^{times}|=varphi(n) ordn(g)=Zn×=φ(n),对于质数 p p p,也就是说 g i   m o d   p , 0 ≤ i < p g^ibmod{p},0le i<p gimodp,0i<p时的结果互不相同。
n n n有原根的充要条件: n = 2 , 4 , p a , 2 ∗ p a n=2,4,p^a,2*p^a n=2,4,pa,2pa
离散对数: g t ≡ a ( m o d n ) , i n d n , g ( a ) = t g^tequiv apmod n,ind_{n,g}(a)=t gta(modn),indn,g(a)=t
因为 g g g是原根,所以 g t gt gt φ ( n ) varphi(n) φ(n)一个周期,可以取到 ∣ Z × n ∣ |Ztimes n| Z×n的所有元素对于 n n n是质数时,就是得到 [ 1 , n − 1 ] [1,n-1] [1,n1]的所有数,就是 [ 0 , n − 2 ] [0,n-2] [0,n2] [ 1 , n − 1 ] [1,n-1] [1,n1]的映射,离散对数满足对数的相关性质。
求原根可以证明满足 g r ≡ 1 ( m o d p ) g^requiv1pmod{p} gr1(modp)的最小的 r r r一定是 p − 1 p-1 p1的约数,对于质数 p p p,质因子分解 p − 1 p-1 p1,若 g ( p − 1 ) / p i ≠ 1 ( m o d p ) g^{(p-1)/pi}ne1pmod{p} g(p1)/pi=1(modp)恒成立, g g g p p p的原根

NTT

对于质数 p = q n + 1 , ( n = 2 m ) p=qn+1,(n=2^m) p=qn+1,(n=2m),原根 g g g满足 g q n ≡ 1 ( m o d p ) g^{qn}equiv 1pmod{p} gqn1(modp)看作 ω n omega_n ωn的等价,则其满足相似的性质,比如 g n n ≡ 1 ( m o d p ) , g n n / 2 ≡ − 1 ( m o d p ) g_n^nequiv1pmod p,g_n^{n/2}equiv-1pmod{p} gnn1(modp),gnn/21(modp)
可以将 g q n g^{qn} gqn等价为 e 2 π n e^{2pi n} e2πn,迭代到长度 l l l时, ω n = g l = g p − 1 p − 1 l omega_n=g_l=g_{p-1}^{frac{p-1}{l}} ωn=gl=gp1lp1

#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<map>
#include<set>
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=10*x+ch-'0';ch=getchar();}
return x*f;
}
void print(int x)
{if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar(x%10+'0');}
const int N=300100,P=998244353;
inline int qpow(int x,int y)
{
int res(1);
while(y)
{
if(y&1) res=1ll*res*x%P;
x=1ll*x*x%P;
y>>=1;
}
return res;
}
int r[N];
void ntt(int *x,int lim,int opt)
{
register int i,j,k,m,gn,g,tmp;
for(i=0;i<lim;++i)
if(r[i]<i)
swap(x[i],x[r[i]]);
for(m=2;m<=lim;m<<=1)
{
k=m>>1;
gn=qpow(3,(P-1)/m);
for(i=0;i<lim;i+=m)
{
g=1;
for(j=0;j<k;++j,g=1ll*g*gn%P)
{
tmp=1ll*x[i+j+k]*g%P;
x[i+j+k]=(x[i+j]-tmp+P)%P;
x[i+j]=(x[i+j]+tmp)%P;
}
}
}
if(opt==-1)
{
reverse(x+1,x+lim);
register int inv=qpow(lim,P-2);
for(i=0;i<lim;++i)
x[i]=1ll*x[i]*inv%P;
}
}
int A[N],B[N],C[N];
char a[N],b[N];
int main()
{
register int i,lim(1),n;
scanf("%s",&a);
n=strlen(a);
for(i=0;i<n;++i) A[i]=a[n-i-1]-'0';
while(lim<(n<<1)) lim<<=1;
scanf("%s",&b);
n=strlen(b);
for(i=0;i<n;++i) B[i]=b[n-i-1]-'0';
while(lim<(n<<1)) lim<<=1;
for(i=0;i<lim;++i)
r[i]=(i&1)*(lim>>1)+(r[i>>1]>>1);
ntt(A,lim,1);ntt(B,lim,1);
for(i=0;i<lim;++i)
C[i]=1ll*A[i]*B[i]%P;
ntt(C,lim,-1);
int len(0);
for(i=0;i<lim;++i)
{
if(C[i]>=10)
len=i+1,
C[i+1]+=C[i]/10,C[i]%=10;
if(C[i]) len=max(len,i);
}
while(C[len]>=10)
C[len+1]+=C[len]/10,C[len]%=10,len++;
for(i=len;~i;--i)
putchar(C[i]+'0');
puts("");
return 0;
}

快速沃尔什变换(FWT)

最后

以上就是舒适水蜜桃为你收集整理的多项式多项式的全部内容,希望文章能够帮你解决多项式多项式所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(49)

评论列表共有 0 条评论

立即
投稿
返回
顶部