概述
多项式
前置知识
多项式的度:
多项式 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 g≤deg f
则称
g
(
x
)
g(x)
g(x)为
f
(
x
)
f(x)
f(x)在模
x
n
x^n
xn意义下的逆元,记作
f
−
1
(
x
)
f^{-1}(x)
f−1(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 f−deg 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
n−1次多项式记为
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=i∏xi−xjx−xj)
所以
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=1∑nyi×(j=i∏xi−xjx−xj)
代入
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=1∑nyi×(j=i∏xi−xjk−xj)
快速傅里叶变换(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+a0⇔f(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,0≤k<n,表示复数域上单位圆被
n
n
n等分后的第
k
k
k个,从0开始。由复数的性质可知
(
ω
n
k
)
n
∗
i
=
1
(omega_n^k)^{n*i}=1
(ωnk)n∗i=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[n−1]⎦⎥⎥⎥⎥⎥⎥⎤=====⎣⎢⎢⎢⎢⎢⎢⎢⎡1111…11ωn1ωn2ωn3…ωnn−11ωn2ωn4ωn6…ωn2(n−1)1ωn3ωn6ωn9…ωn3(n−1)………………1ωnn−1ωn2(n−1)ωn3(n−1)…ωn(n−1)2⎦⎥⎥⎥⎥⎥⎥⎥⎤⎣⎢⎢⎢⎢⎢⎢⎡a[0]a[1]a[2]a[3]…a[n−1]⎦⎥⎥⎥⎥⎥⎥⎤
这个矩阵是范德蒙德矩阵,其逆矩阵是每一项求倒数后除以
n
n
n,然后发现
ω
n
i
omega_n^i
ωni倒数是就是
ω
n
−
i
omega_n^{-i}
ωn−i。
所以把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(on∗2π/n)+isin(on∗2π/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
S′⊂S,则
(
S
′
,
⊕
)
(S',oplus)
(S′,⊕)是
(
S
,
⊕
)
(S,oplus)
(S,⊕)的子群
拉格朗日定理:
∣
S
′
∣
|S'|
∣S′∣是
∣
S
∣
|S|
∣S∣的因子
生成子群:
a
∈
S
ain S
a∈S的生成子群
<
a
>
=
{
a
(
k
)
,
k
≥
1
}
left<aright>={a^{(k)},kge 1}
⟨a⟩={a(k),k≥1},
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],n∈Zn: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,0≤i<p时的结果互不相同。
模
n
n
n有原根的充要条件:
n
=
2
,
4
,
p
a
,
2
∗
p
a
n=2,4,p^a,2*p^a
n=2,4,pa,2∗pa
离散对数:
g
t
≡
a
(
m
o
d
n
)
,
i
n
d
n
,
g
(
a
)
=
t
g^tequiv apmod n,ind_{n,g}(a)=t
gt≡a(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,n−1]的所有数,就是
[
0
,
n
−
2
]
[0,n-2]
[0,n−2]到
[
1
,
n
−
1
]
[1,n-1]
[1,n−1]的映射,离散对数满足对数的相关性质。
求原根可以证明满足
g
r
≡
1
(
m
o
d
p
)
g^requiv1pmod{p}
gr≡1(modp)的最小的
r
r
r一定是
p
−
1
p-1
p−1的约数,对于质数
p
p
p,质因子分解
p
−
1
p-1
p−1,若
g
(
p
−
1
)
/
p
i
≠
1
(
m
o
d
p
)
g^{(p-1)/pi}ne1pmod{p}
g(p−1)/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}
gqn≡1(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}
gnn≡1(modp),gnn/2≡−1(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=gp−1lp−1。
#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)
最后
以上就是舒适水蜜桃为你收集整理的多项式多项式的全部内容,希望文章能够帮你解决多项式多项式所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复