-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathPolyOp_new.cpp
89 lines (89 loc) · 2.85 KB
/
PolyOp_new.cpp
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
struct PolyOp {
#define FOR(i, c) for (int i = 0; i < (c); ++i)
NTT<P, root, MAXN> ntt;
static int nxt2k(int x) {
int i = 1; for (; i < x; i <<= 1); return i;
}
// c[i]=sum{j=0~i}a[j]*b[i-j] -> c[i+j]+=a[i]*b[j](加分卷積)
// if c[i-j]+=a[i]*b[j] (減法卷積)
// (轉換成加法捲積) -> reverse(a); c=mul(a,b); reverse( c );
void Mul(int n, LL a[], int m, LL b[], LL c[]) {
static LL aa[MAXN], bb[MAXN];
int N = nxt2k(n+m);
copy(a, a+n, aa); fill(aa+n, aa+N, 0);
copy(b, b+m, bb); fill(bb+m, bb+N, 0);
ntt.tran(N, aa); ntt.tran(N, bb);
FOR(i, N) c[i] = aa[i] * bb[i] % P;
ntt.tran(N, c, 1);
}
void Inv(int n, LL a[], LL b[]) {
// ab = aa^-1 = 1 mod x^(n/2)
// (b - a^-1)^2 = 0 mod x^n
// bb - a^-2 + 2 ba^-1 = 0
// bba - a^-1 + 2b = 0
// bba + 2b = a^-1
static LL tmp[MAXN];
if (n == 1) {b[0] = ntt.inv(a[0], P); return;}
Inv((n+1)/2, a, b);
int N = nxt2k(n*2);
copy(a, a+n, tmp);
fill(tmp+n, tmp+N, 0);
fill(b+n, b+N, 0);
ntt.tran(N, tmp); ntt.tran(N, b);
FOR(i, N) {
LL t1 = (2 - b[i] * tmp[i]) % P;
if (t1 < 0) t1 += P;
b[i] = b[i] * t1 % P;
}
ntt.tran(N, b, 1);
fill(b+n, b+N, 0);
}
void Div(int n, LL a[], int m, LL b[], LL d[], LL r[]) {
// Ra = Rb * Rd mod x^(n-m+1)
// Rd = Ra * Rb^-1 mod
static LL aa[MAXN], bb[MAXN], ta[MAXN], tb[MAXN];
if (n < m) {copy(a, a+n, r); fill(r+n, r+m, 0); return;}
// d: n-1 - (m-1) = n-m (n-m+1 terms)
copy(a, a+n, aa); copy(b, b+m, bb);
reverse(aa, aa+n); reverse(bb, bb+m);
Inv(n-m+1, bb, tb);
Mul(n-m+1, ta, n-m+1, tb, d);
fill(d+n-m+1, d+n, 0); reverse(d, d+n-m+1);
// r: m-1 - 1 = m-2 (m-1 terms)
Mul(m, b, n-m+1, d, ta);
FOR(i, n) { r[i] = a[i] - ta[i]; if (r[i] < 0) r[i] += P; }
}
void dx(int n, LL a[], LL b[]) { REP(i, 1, n-1) b[i-1] = i * a[i] % P; }
void Sx(int n, LL a[], LL b[]) {
b[0] = 0;
FOR(i, n) b[i+1] = a[i] * ntt.inv(i+1, P) % P;
}
void Ln(int n, LL a[], LL b[]) {
// Integral a' a^-1 dx
static LL a1[MAXN], a2[MAXN], b1[MAXN];
int N = nxt2k(n*2);
dx(n, a, a1); Inv(n, a, a2);
Mul(n-1, a1, n, a2, b1);
Sx(n+n-1-1, b1, b);
fill(b+n, b+N, 0);
}
void Exp(int n, LL a[], LL b[]) {
// Newton method to solve g(a(x)) = ln b(x) - a(x) = 0
// b' = b - g(b(x)) / g'(b(x))
// b' = b (1 - lnb + a)
static LL lnb[MAXN], c[MAXN], tmp[MAXN];
assert(a[0] == 0); // dont know exp(a[0]) mod P
if (n == 1) {b[0] = 1; return;}
Exp((n+1)/2, a, b);
fill(b+(n+1)/2, b+n, 0);
Ln(n, b, lnb);
fill(c, c+n, 0); c[0] = 1;
FOR(i, n) {
c[i] += a[i] - lnb[i];
if (c[i] < 0) c[i] += P;
if (c[i] >= P) c[i] -= P;
}
Mul(n, b, n, c, tmp);
copy(tmp, tmp+n, b);
}
} polyop;