若
G ( F 0 ( x ) ) ≡ 0 ( m o d x 2 t ) G(F_0(x))\equiv 0(mod\ x^{2^t}) G(F0(x))≡0(mod x2t)
牛顿迭代
F ( x ) ≡ F 0 ( x ) − G ( F 0 ( x ) ) G ′ ( F 0 ( x ) ) ( m o d x 2 t + 1 ) F(x)\equiv F_0(x)-\frac{G(F_0(x))}{G'(F_0(x))}(mod\ x^{2^{t+1}}) F(x)≡F0(x)−G′(F0(x))G(F0(x))(mod x2t+1)
以下多数都可以牛顿迭代公式一步得到
给定 A ( x ) A(x) A(x)求满足 A ( x ) ∗ B ( x ) = 1 A(x)*B(x)=1 A(x)∗B(x)=1的 B ( x ) B(x) B(x)
写成
A ( x ) ∗ B ( x ) = 1 ( m o d x n ) A(x)*B(x)=1(mod \ x^n) A(x)∗B(x)=1(mod xn)
我们会求 A ( x ) ∗ B ( x ) = 1 ( m o d x 1 ) A(x)*B(x)=1(mod \ x^1) A(x)∗B(x)=1(mod x1)
然后我们考虑求 A ( x ) ∗ B ( x ) = 1 ( m o d x t ) A(x)*B(x)=1(mod \ x^t) A(x)∗B(x)=1(mod xt)
( A ( x ) ∗ B ( x ) − 1 ) 2 = 0 ( m o d x 2 t ) (A(x)*B(x)-1)^2=0(mod \ x^{2t}) (A(x)∗B(x)−1)2=0(mod x2t)
A ( x ) ( 2 B ( x ) − A ( x ) ∗ B 2 ( x ) ) = 1 ( m o d x 2 t ) A(x)(2B(x)-A(x)*B^2(x))=1(mod \ x^{2t}) A(x)(2B(x)−A(x)∗B2(x))=1(mod x2t)
把 2 B ( x ) − A ( x ) ∗ B 2 ( x ) 2B(x)-A(x)*B^2(x) 2B(x)−A(x)∗B2(x)当作新的 B B B倍增算
从 m o d x 1 mod \ x^1 mod x1倍增到大于等于 n n n
# include
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int _(4e5 + 5);
const int Zsy(998244353);
const int Phi(998244352);
const int G(3);
IL int Input(){
RG int x = 0, z = 1; RG char c = getchar();
for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
return x * z;
}
IL int Pow(RG ll x, RG ll y){
RG ll ret = 1;
for(; y; x = x * x % Zsy, y >>= 1)
if(y & 1) ret = ret * x % Zsy;
return ret;
}
int N, r[_], l, A[_], B[_];
IL void NTT(RG int *P, RG int opt){
for(RG int i = 0; i < N; ++i) if(i < r[i]) swap(P[i], P[r[i]]);
for(RG int i = 1; i < N; i <<= 1){
RG int wn = Pow(G, Phi / (i << 1));
if(opt == -1) wn = Pow(wn, Zsy - 2);
for(RG int j = 0, p = i << 1; j < N; j += p)
for(RG int w = 1, k = 0; k < i; w = 1LL * w * wn % Zsy, ++k){
RG int X = P[k + j], Y = 1LL * w * P[k + j + i] % Zsy;
P[k + j] = (X + Y) % Zsy, P[k + j + i] = (X - Y + Zsy) % Zsy;
}
}
}
IL void Mul(RG int *a, RG int *b, RG int len){
for(l = 0, N = 1, len += len - 1; N <= len; N <<= 1) ++l;
for(RG int i = 0; i < N; ++i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
for(RG int i = 0; i < N; ++i) A[i] = B[i] = 0;
for(RG int i = 0; i <= len >> 1; ++i) A[i] = a[i], B[i] = b[i];
NTT(A, 1), NTT(B, 1);
for(RG int i = 0; i < N; ++i) A[i] = 1LL * A[i] * B[i] % Zsy * B[i] % Zsy;
NTT(A, -1);
RG int inv = Pow(N, Zsy - 2);
for(RG int i = 0; i <= len; ++i) A[i] = 1LL * A[i] * inv % Zsy;
}
int n, a[_], b[_], c[_], m;
int main(RG int argc, RG char *argv[]){
n = Input();
for(RG int i = 0; i < n; ++i) a[i] = Input() % Zsy;
for(m = 1; m < n; m <<= 1);
b[0] = Pow(a[0], Zsy - 2);
for(RG int t = 2; t <= m; t <<= 1){
for(RG int i = 0; i < t; ++i) c[i] = b[i];
Mul(a, b, t);
for(RG int i = 0; i < t; ++i)
b[i] = ((c[i] + c[i]) % Zsy - A[i] + Zsy) % Zsy;
}
for(RG int i = 0; i < n; ++i) printf("%d ", b[i]);
return puts(""), 0;
}
已知 n n n次多项式 A ( x ) A(x) A(x)和 m m m次多项式 B ( x ) B(x) B(x), n > m n>m n>m
求 A ( x ) A(x) A(x)除以 B ( x ) B(x) B(x)的商 C ( x ) C(x) C(x)及余式 D ( x ) D(x) D(x)
也就是
A ( x ) = B ( x ) C ( x ) + D ( x ) A(x)=B(x)C(x)+D(x) A(x)=B(x)C(x)+D(x)
A ( 1 x ) = B ( 1 x ) C ( 1 x ) + D ( 1 x ) A(\frac{1}{x})=B(\frac{1}{x})C(\frac{1}{x})+D(\frac{1}{x}) A(x1)=B(x1)C(x1)+D(x1)
x n A ( 1 x ) = ( x m B ( 1 x ) ) ( x n − m C ( 1 x ) ) + x n − m + 1 ( x n − 1 D ( 1 x ) ) x^nA(\frac{1}{x})=(x^mB(\frac{1}{x}))(x^{n-m}C(\frac{1}{x}))+x^{n-m+1}(x^{n-1}D(\frac{1}{x})) xnA(x1)=(xmB(x1))(xn−mC(x1))+xn−m+1(xn−1D(x1))
对 x n − m + 1 x^{n-m+1} xn−m+1取模
A R ( x ) = B R ( x ) C R ( x ) ( m o d x n − m + 1 ) A^R(x)=B^R(x)C^R(x)(mod \ x^{n-m+1}) AR(x)=BR(x)CR(x)(mod xn−m+1)
R R R表示把系数倒置,即 s w a p swap swap前后
那么可以多项式求逆,再相乘得到 C R ( x ) C^R(x) CR(x)
然后去掉 R R R带入原式相乘再相减得到 D ( x ) D(x) D(x)
# include
# define IL inline
# define RG register
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
IL int Input(){
RG int x = 0, z = 1; RG char c = getchar();
for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
return x * z;
}
const int mod(998244353);
const int phi(998244352);
const int maxn(8e5 + 5);
const int g(3);
IL int Pow(RG ll x, RG ll y){
RG ll ret = 1;
for(; y; y >>= 1, x = x * x % mod)
if(y & 1) ret = ret * x % mod;
return ret;
}
int x[maxn], y[maxn], z[maxn], s[maxn], c[maxn], n, m, a[maxn], b[maxn], r[maxn], len;
IL void NTT(RG int *p, RG int m, RG int opt){
RG int l = 0, n = 1;
for(; n < m; n <<= 1) ++l;
for(RG int i = 0; i < n; ++i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
for(RG int i = 0; i < n; ++i) if(r[i] < i) swap(p[r[i]], p[i]);
for(RG int i = 1; i < n; i <<= 1){
RG int wn = Pow(g, phi / (i << 1));
if(opt == -1) wn = Pow(wn, mod - 2);
for(RG int j = 0, t = i << 1; j < n; j += t)
for(RG int k = 0, w = 1; k < i; ++k, w = 1LL * w * wn % mod){
RG int x = p[j + k], y = 1LL * w * p[j + k + i] % mod;
p[j + k] = (x + y) % mod, p[j + k + i] = (x - y + mod) % mod;
}
}
if(opt == -1){
RG int inv = Pow(n, mod - 2);
for(RG int i = 0; i < n; ++i) p[i] = 1LL * p[i] * inv % mod;
}
}
IL void Inv(RG int *p, RG int *q, RG int num){
if(num == 1){
q[0] = Pow(p[0], mod - 2);
return;
}
Inv(p, q, num >> 1);
for(RG int i = 0; i < num; ++i) a[i] = p[i], b[i] = q[i];
RG int l = num << 1;
NTT(a, l, 1), NTT(b, l, 1);
for(RG int i = 0; i < l; ++i) a[i] = 1LL * a[i] * b[i] % mod * b[i] % mod;
NTT(a, l, -1);
for(RG int i = 0; i < num; ++i) q[i] = ((2 * q[i] - a[i]) % mod + mod) % mod;
for(RG int i = 0; i < l; ++i) a[i] = b[i] = 0;
}
int main(){
n = Input(), m = Input();
for(RG int i = 0; i <= n; ++i) y[i] = Input();
for(RG int i = 0; i <= m; ++i) x[i] = Input();
reverse(x, x + m + 1), reverse(y, y + n + 1);
for(RG int i = 0; i <= n - m; ++i) s[i] = x[i];
for(len = 1; len <= n - m; len <<= 1);
Inv(s, z, len);
for(len = 1; len <= (n - m) << 1; len <<= 1);
for(RG int i = 0; i <= n - m; ++i) a[i] = y[i];
for(RG int i = 0; i <= n - m; ++i) b[i] = z[i];
len <<= 1;
NTT(a, len, 1), NTT(b, len, 1);
for(RG int i = 0; i < len; ++i) b[i] = 1LL * b[i] * a[i] % mod;
NTT(b, len, -1), reverse(b, b + n - m + 1);
for(RG int i = 0; i <= n - m; ++i) c[i] = b[i], printf("%d ", c[i]);
puts(""), reverse(y, y + n + 1), reverse(x, x + m + 1);
for(RG int i = 0; i < len; ++i) a[i] = b[i] = 0;
for(len = 1; len <= n; len <<= 1);
for(RG int i = 0; i <= n; ++i) a[i] = x[i];
for(RG int i = 0; i <= n - m; ++i) b[i] = c[i];
NTT(a, len, 1), NTT(b, len, 1);
for(RG int i = 0; i < len; ++i) a[i] = 1LL * a[i] * b[i] % mod;
NTT(a, len, -1);
for(RG int i = 0; i < m; ++i) y[i] = (y[i] - a[i] + mod) % mod, printf("%d ", y[i]);
return 0;
}
给定 B ( x ) B(x) B(x),求 A ( x ) A(x) A(x)使 A 2 ( x ) = B ( x ) A^2(x)=B(x) A2(x)=B(x)
写成
A 2 ( x ) = B ( x ) ( m o d x n ) A^2(x)=B(x) (mod \ x^n) A2(x)=B(x)(mod xn)
然后
A 2 ( x ) = B ( x ) ( m o d x 1 ) A^2(x)=B(x)(mod \ x^1) A2(x)=B(x)(mod x1)
是可以求的,好像是什么二次剩余
留坑在这里以后补
考虑求
A 2 ( x ) = B ( x ) ( m o d x 2 t ) A^2(x)=B(x)(mod \ x^{2t}) A2(x)=B(x)(mod x2t)
令
C 2 ( x ) = B ( x ) ( m o d x t ) C^2(x)=B(x)(mod \ x^t) C2(x)=B(x)(mod xt)
那么
( A 2 ( x ) − C 2 ( x ) ) 2 = 0 ( m o d x 2 t ) (A^2(x)-C^2(x))^2=0(mod \ x^{2t}) (A2(x)−C2(x))2=0(mod x2t)
A 4 ( x ) − 2 A 2 ( x ) C 2 ( x ) + C 4 ( x ) = 0 ( m o d x 2 t ) A^4(x)-2A^2(x)C^2(x)+C^4(x)=0(mod \ x^{2t}) A4(x)−2A2(x)C2(x)+C4(x)=0(mod x2t)
A 2 ( x ) = A 4 ( x ) + C 4 ( x ) 2 C 2 ( x ) ( m o d x 2 t ) A^2(x)=\frac{A^4(x)+C^4(x)}{2C^2(x)}(mod \ x^{2t}) A2(x)=2C2(x)A4(x)+C4(x)(mod x2t)
2 A 2 ( x ) = A 4 ( x ) + 2 C 2 ( x ) A 2 ( x ) + C 4 ( x ) 2 C 2 ( x ) ( m o d x 2 t ) 2A^2(x)=\frac{A^4(x)+2C^2(x)A^2(x)+C^4(x)}{2C^2(x)}(mod \ x^{2t}) 2A2(x)=2C2(x)A4(x)+2C2(x)A2(x)+C4(x)(mod x2t)
A 2 ( x ) = ( A 2 ( x ) + C 2 ( x ) ) 2 ( 2 C ( x ) ) 2 ( m o d x 2 t ) A^2(x)=\frac{(A^2(x)+C^2(x))^2}{(2C(x))^2}(mod \ x^{2t}) A2(x)=(2C(x))2(A2(x)+C2(x))2(mod x2t)
A ( x ) = B ( x ) + C 2 ( x ) 2 C ( x ) ( m o d x 2 t ) A(x)=\frac{B(x)+C^2(x)}{2C(x)}(mod \ x^{2t}) A(x)=2C(x)B(x)+C2(x)(mod x2t)
同样的还是倍增求
设 B ( x ) = l n ( A ( x ) ) B(x)=ln(A(x)) B(x)=ln(A(x))
同时求导
就是
B ′ ( x ) = A ′ ( x ) A ( x ) B'(x)=\frac{A'(x)}{A(x)} B′(x)=A(x)A′(x)
那么多项式求导,然后多项式求逆,然后多项式积分就好了
设 B ( x ) = e A ( x ) B(x)=e^{A(x)} B(x)=eA(x)
那么
l n ( B ( x ) ) = A ( x ) ln(B(x))=A(x) ln(B(x))=A(x)
牛顿迭代
得
B ( x ) ( m o d 2 t + 1 ) = B ( x ) ( m o d 2 t ) ( 1 − l n ( B ( x ) ( m o d 2 t ) ) + A ( x ) ) B(x)(mod\ 2^{t+1})=B(x)(mod\ 2^t)(1-ln(B(x)(mod\ 2^t))+A(x)) B(x)(mod 2t+1)=B(x)(mod 2t)(1−ln(B(x)(mod 2t))+A(x))
设 B ( x ) = A k ( x ) B(x)=A^k(x) B(x)=Ak(x)
那么 l n ( B ( x ) ) = k l n ( A ( x ) ) ln(B(x))=kln(A(x)) ln(B(x))=kln(A(x))
然后就是求 l n ln ln然后 e x p exp exp就好了
COGS2189. [HZOI 2015] 帕秋莉的超级多项式
# include
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
IL int Input(){
RG int x = 0, z = 1; RG char c = getchar();
for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
return x * z;
}
const int maxn(8e5 + 5);
const int mod(998244353);
const int phi(998244352);
const int inv2(499122177);
const int g(3);
int a[maxn], b[maxn], c[maxn], d[maxn], r[maxn];
IL int Pow(RG ll x, RG ll y){
RG ll ret = 1;
for(; y; y >>= 1, x = x * x % mod)
if(y & 1) ret = ret * x % mod;
return ret;
}
IL void NTT(RG int *p, RG int m, RG int opt){
RG int n = 1, l = 0;
for(; n < m; n <<= 1) ++l;
for(RG int i = 0; i < n; ++i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
for(RG int i = 0; i < n; ++i) if(r[i] < i) swap(p[i], p[r[i]]);
for(RG int i = 1; i < n; i <<= 1){
RG int t = i << 1, wn = Pow(g, phi / t);
if(opt == -1) wn = Pow(wn, mod - 2);
for(RG int j = 0; j < n; j += t)
for(RG int k = 0, w = 1; k < i; ++k, w = 1LL * w * wn % mod){
RG int x = p[k + j], y = 1LL * w * p[k + j + i] % mod;
p[k + j] = (x + y) % mod, p[k + j + i] = (x - y + mod) % mod;
}
}
if(opt == -1){
RG int inv = Pow(n, mod - 2);
for(RG int i = 0; i < n; ++i) p[i] = 1LL * p[i] * inv % mod;
}
}
IL void Inv(RG int *p, RG int *q, RG int len){
if(len == 1){
q[0] = Pow(p[0], mod - 2);
return;
}
Inv(p, q, len >> 1);
for(RG int i = 0; i < len; ++i) a[i] = p[i], b[i] = q[i];
RG int tmp = len << 1;
NTT(a, tmp, 1), NTT(b, tmp, 1);
for(RG int i = 0; i < tmp; ++i) a[i] = 1LL * a[i] * b[i] % mod * b[i] % mod;
NTT(a, tmp, -1);
for(RG int i = 0; i < len; ++i) q[i] = ((2 * q[i] - a[i]) % mod + mod) % mod;
for(RG int i = 0; i < tmp; ++i) a[i] = b[i] = 0;
}
IL void Sqrt(RG int *p, RG int *q, RG int len){
if(len == 1){
q[0] = sqrt(p[0]); //???
return;
}
Sqrt(p, q, len >> 1), Inv(q, c, len);
RG int tmp = len << 1;
for(RG int i = 0; i < len; ++i) a[i] = p[i];
NTT(a, tmp, 1), NTT(c, tmp, 1);
for(RG int i = 0; i < tmp; ++i) a[i] = 1LL * a[i] * c[i] % mod;
NTT(a, tmp, -1);
for(RG int i = 0; i < len; ++i) q[i] = 1LL * (q[i] + a[i]) % mod * inv2 % mod;
for(RG int i = 0; i < tmp; ++i) a[i] = c[i] = 0;
}
IL void ICalc(RG int *p, RG int *q, RG int len){
q[len - 1] = 0;
for(RG int i = 1; i < len; ++i) q[i - 1] = 1LL * p[i] * i % mod;
}
IL void Calc(RG int *p, RG int *q, RG int len){
q[0] = 0;
for(RG int i = 1; i < len; ++i) q[i] = 1LL * Pow(i, mod - 2) * p[i - 1] % mod;
}
IL void Ln(RG int *p, RG int *q, RG int len){
Inv(p, c, len), ICalc(p, a, len);
RG int tmp = len << 1;
NTT(c, tmp, 1), NTT(a, tmp, 1);
for(RG int i = 0; i < tmp; ++i) c[i] = 1LL * c[i] * a[i] % mod;
NTT(c, tmp, -1), Calc(c, q, len);
for(RG int i = 0; i < tmp; ++i) a[i] = c[i] = 0;
}
IL void Exp(RG int *p, RG int *q, RG int len){
if(len == 1){
q[0] = 1;
return;
}
Exp(p, q, len >> 1), Ln(q, b, len);
for(RG int i = 0; i < len; ++i) b[i] = (mod - b[i] + p[i]) % mod, c[i] = q[i];
b[0] = (b[0] + 1) % mod;
RG int tmp = len << 1;
NTT(b, tmp, 1), NTT(c, tmp, 1);
for(RG int i = 0; i < tmp; ++i) b[i] = 1LL * b[i] * c[i] % mod;
NTT(b, tmp, -1);
for(RG int i = 0; i < len; ++i) q[i] = b[i];
for(RG int i = 0; i < tmp; ++i) b[i] = c[i] = 0;
}
IL void CalcPow(RG int *p, RG int *q, RG int len, RG int y){
Ln(p, d, len);
for(RG int i = 0; i < len; ++i) d[i] = 1LL * d[i] * y % mod;
Exp(d, q, len);
for(RG int i = 0; i < len; ++i) d[i] = 0;
}
int f[maxn], h[maxn], n, k, len;
IL void Record(){
for(RG int i = 0; i < len; ++i) f[i] = h[i], h[i] = 0;
}
int main(){
freopen("polynomial.in", "r", stdin);
freopen("polynomial.out", "w", stdout);
n = Input() - 1, k = Input();
for(RG int i = 0; i <= n; ++i) f[i] = Input();
for(len = 1; len <= n; len <<= 1);
Sqrt(f, h, len), Record();
Inv(f, h, len), Record();
Calc(f, h, n + 1), Record();
Exp(f, h, len), Record();
Inv(f, h, len), Record();
f[0] = (f[0] + 1) % mod;
Ln(f, h, len), Record();
f[0] = (f[0] + 1) % mod;
CalcPow(f, h, len, k), Record();
ICalc(f, h, n + 1);
for(RG int i = 0; i <= n; ++i) printf("%d ", h[i]);
return 0;
}