历史遗迹

这里存一些被淘汰掉的板子之类的东西

2021-04-03

FFT

复数类操作:

1
2
3
complex<double>m;
m.real();m.imag();//获取实部虚部的值
m.real(114);m.imag(514);//为实部虚部赋值

需要继续理解迭代算法.现在这就是个板子

被卡常时记得别用long double

调用FFT(A,1)\(A\)变为\(A\)\(DFT\),调用FFT(A,-1)\(DFT^{-1}\).

\(A\)是复数数组,其实部初始是多项式系数.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
typedef double ld;
typedef complex<ld> cld;
typedef vector<cld> Poly;
const int maxn = 8E6+10;
const ld PI = acos(-1.0);
int rev[maxn];
void init(Poly & A,int n){
int size = 1;
while(size <= n)size *= 2;
A.assign(size*2,0);
}
void FFT_init(int n){
int S = log2(n);
for(int i = 0;i < n;i++)rev[i] = (rev[i>>1] >> 1) | ((i & 1) << (S - 1));
}
void FFT(Poly & A,int type){
int n = A.size();
for(int i = 0;i < n;i++)if(i < rev[i])swap(A[i],A[rev[i]]);
for(int i = 1;i < n;i *= 2){
cld Wn(cos(PI/i),type*sin(PI/i));
for(int j = 0;j < n;j += i*2){
cld W(1,0);
for(int k = 0;k < i;k++){
cld facx = A[j+k],facy = W*A[j+k+i];
A[j+k] = facx + facy;
A[j+k+i] = facx - facy;
W *= Wn;
}
}
}
if(type == -1)for(int i = 0;i < (int)A.size();i++)A[i].real((int)(A[i].real()/A.size() + 0.5));
}

卷积

\[ C[i] = \sum_{j = 0}^iA[j]B[i-j] \]

卷积等同于多项式乘积

输入两个多项式\(A,B\)的系数,求出其乘积:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
signed main(){
ios::sync_with_stdio(0);
cin.tie(nullptr);
int n,m;
cin >> n >> m;
int d = n+m;
Poly A,B;
init(A,max(n,m));
init(B,max(n,m));
FFT_init(A.size());
for(int i = 0;i <= n;i++)cin >> A[i];
for(int i = 0;i <= m;i++)cin >> B[i];
FFT(A,1);
FFT(B,1);
for(int i = 0;i < (int)A.size();i++)A[i] *= B[i];
FFT(A,-1);
for(int i = 0;i <= d;i++)cout << (int)(A[i].real()/A.size() + 0.5)<< " ";
return 0;
}

手写复数类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct node{
double x, y ;
node (double xx = 0, double yy = 0){
x = xx, y = yy ;
}
};
node operator * (node J, node Q){
return node(J.x * Q.x - J.y * Q.y , J.x * Q.y + J.y * Q.x);
}
node operator + (node J, node Q){
return node(J.x + Q.x , J.y + Q.y);
}
node operator - (node J, node Q){
return node(J.x - Q.x , J.y - Q.y );
}

NTT

从OI-wiki抄来的, 用法和上面的FFT一致. 记得自己手写一遍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
typedef vector<int> Poly;
int rev[maxn];
void init(vector<int> & x,int n){
int size = 1;
while(size <= n)size *= 2;
x.assign(size*2,0);
}
void NTT_init(int lim){
for (int i = 0; i < lim; ++i) rev[i] = (i & 1) * (lim >> 1) + (rev[i >> 1] >> 1);
}
void NTT(vector<int> & A, int opt) {
int lim = A.size();
int i, j, k, m, gn, g, tmp;
for(i = 0; i < lim; ++i)if (rev[i] < i) swap(A[i], A[rev[i]]);
for(m = 2; m <= lim; m <<= 1) {
k = m >> 1;
gn = Pow(3,(p - 1) / m);//998244353的原根是3
for(i = 0; i < lim; i += m) {
g = 1;
for (j = 0; j < k; ++j, g = 1ll * g * gn % p) {
tmp = 1ll * A[i + j + k] * g % p;
A[i + j + k] = (A[i + j] - tmp + p) % p;
A[i + j] = (A[i + j] + tmp) % p;
}
}
}
if(opt == -1){
auto it = A.begin();it++;
reverse(it,A.end());
int inv = Pow(lim,p-2);
for(i = 0; i < lim; ++i) A[i] = 1ll * A[i] * inv % p;
}
}

与FFT的区别在点值表示法相乘时, NTT需要取模. 另外注意原根需与模数对应

1
for(int i = 0;i < (int)A.size();i++)A[i] = 1ll*A[i]*B[i]%p;