mirror of
https://github.com/Kiritow/OJ-Problems-Source.git
synced 2024-03-22 13:11:29 +08:00
635 lines
22 KiB
C++
635 lines
22 KiB
C++
//快速幂
|
||
ll powMod(ll a, ll b, ll m) {
|
||
ll r = 1;
|
||
for (a %= m; b; b >>= 1) { if (b & 1) { r = r * a % m; } a = a * a % m; }
|
||
return r;
|
||
}
|
||
//素数筛
|
||
//Eratosthenes O(nloglogn)
|
||
const int N = 10000000; //~110ms
|
||
bitset<N> isprime;
|
||
void getPrime() {
|
||
isprime.set(); isprime[0] = isprime[1] = false;
|
||
for (int i = 2; i < N; i++) {
|
||
if (isprime[i]) {
|
||
for (ll j = (ll)i * i; j < N; j += i) { isprime[j] = false; }
|
||
}
|
||
}
|
||
}
|
||
//Euler O(n) prime[0]为个数
|
||
const int N = 10000000; //~110ms
|
||
int prime[N]; //3711111 for [2, 10^9)
|
||
void getPrime() {
|
||
for (int i = 2; i < N; i++) {
|
||
if (!prime[i]) { prime[++prime[0]] = i; }
|
||
for (int j = 1; j <= prime[0] && prime[j] * i < N; j++) {
|
||
prime[prime[j] * i] = 1;
|
||
if (i % prime[j] == 0) { break; }
|
||
}
|
||
}
|
||
}
|
||
//Euler O(n)
|
||
const int N = 10000000; //~95ms
|
||
int prime[N >> 3]; bitset<N> isprime;
|
||
void getPrime() {
|
||
isprime.set(); isprime[0] = isprime[1] = false;
|
||
for (int i = 2; i < N; i++) {
|
||
if (isprime[i]) { prime[++prime[0]] = i; }
|
||
for (int j = 1; j <= prime[0] && prime[j] * i < N; j++) {
|
||
isprime[prime[j] * i] = false;
|
||
if (i % prime[j] == 0) { break; }
|
||
}
|
||
}
|
||
}
|
||
//[a, b]区间内素数个数
|
||
bitset<N> isprime, isprimesmall;
|
||
ll segPrime(ll a, ll b) {
|
||
ll ret = 0; isprime.set(); isprimesmall.set();
|
||
for (int i = 2; (ll)i * i <= b; i++) {
|
||
if (isprimesmall[i]) {
|
||
for (ll j = (ll)i * i; (ll)j * j <= b; j += i) { isprimesmall[j] = false; }
|
||
for (ll j = max(2ll, (a + i - 1) / i)) * i; j <= b; j += i) { isprime[j - a] = false; }
|
||
}
|
||
}
|
||
for (ll i = 0; i <= r - l; i++) { ret += isprime[i]; }
|
||
return ret;
|
||
}
|
||
//分解质因数
|
||
ll factor[100], facCnt;
|
||
void getFactors(ll x) {
|
||
facCnt = 0;
|
||
for (int i = 2, xx = sqrt(x + 0.5); i <= xx; i++) {
|
||
if (x % i == 0) {
|
||
factor[facCnt++] = i;
|
||
while (x % i == 0) { x /= i; }
|
||
}
|
||
}
|
||
if (x != 1) { factor[facCnt++] = x; }
|
||
}
|
||
//分解质因数及个数 预处理素数表
|
||
ll factor[100][2], facCnt;
|
||
void getFactors(ll x) {
|
||
facCnt = 0;
|
||
for (int i = 1; prime[i] <= x / prime[i]; i++) {
|
||
factor[facCnt][1] = 0;
|
||
if (x % prime[i] == 0) {
|
||
factor[facCnt][0] = prime[i];
|
||
while (x % prime[i] == 0) { factor[facCnt][1]++; x /= prime[i]; }
|
||
facCnt++;
|
||
}
|
||
}
|
||
if (x != 1) { factor[facCnt][0] = x; factor[facCnt++][1] = 1; }
|
||
}
|
||
//Miller-Rabin素性测试 素数返回true 错误(伪素数)概率为1/4^Times
|
||
const int Times = 7;
|
||
int WIT[] = {2, 325, 9375, 28178, 450775, 9780504, 1795265022}; //7 bases for n < 2^64
|
||
ll mulMod(ll a, ll b, ll m) {
|
||
ll r = 0;
|
||
for (a %= m, b %= m; b; b >>= 1) { if (b & 1) { r = (r + a) % m; } a = (a << 1) % m; }
|
||
return r;
|
||
}
|
||
ll powMod(ll a, ll b, ll m) {
|
||
ll r = 1;
|
||
for (a %= m; b; b >>= 1) { if (b & 1) { r = mulMod(r, a, m); } a = mulMod(a, a, m); }
|
||
return r;
|
||
}
|
||
bool Miller_Rabin(ll n) {
|
||
if (n == 2) { return true; }
|
||
if (n < 2 || (n & 1) == 0) { return false; }
|
||
ll m = n - 1; int k = 0;
|
||
while ((m & 1) == 0) { k++; m >>= 1; }
|
||
for (int i = 0; i < Times; i++) {
|
||
ll a = WIT[i], x = powMod(a, m, n), y = 0;
|
||
//ll a = rand() % (n - 1) + 1;
|
||
for (int j = 0; j < k; j++, x = y) {
|
||
y = mulMod(x, x, n);
|
||
if (y == 1 && x != 1 && x != n - 1) { return false; }
|
||
}
|
||
if (y != 1) { return false; }
|
||
}
|
||
return true;
|
||
}
|
||
//pollard rho质因素分解
|
||
//对n进行素因子分解, 存入factor, k设置为107左右即可
|
||
ll factor[100], facCnt; //质因素分解结果(无序)
|
||
ll pollard_rho(ll x, ll c) {
|
||
ll i = 1, k = 2, x0 = rand() % (x - 1) + 1, y = x0;
|
||
while (true) {
|
||
x0 = (mulMod(x0, x0, x) + c) % x;
|
||
ll d = llabs(__gcd(y - x0, x));
|
||
if (d != 1 && d != x) { return d; }
|
||
if (y == x0) { return x; }
|
||
if (++i == k) { y = x0; k <<= 1; }
|
||
}
|
||
}
|
||
void findfac(ll n, int k = 107) {
|
||
if (n == 1) { return; }
|
||
if (Miller_Rabin(n)) { factor[facCnt++] = n; return; }
|
||
ll p = n; int c = k;
|
||
while (p >= n) { p = pollard_rho(p, c--); } //k值变化, 防止死循环
|
||
findfac(p, k); findfac(n / p, k);
|
||
}
|
||
//求单个数的欧拉函数
|
||
ll eular(ll n) {
|
||
ll ret = 1;
|
||
while ((n & 1) == 0) { n >>= 1; ret <<= 1; }
|
||
for (ll i = 3; i * i <= n; i += 2) {
|
||
if (n % i == 0) { n /= i; ret *= i - 1; while (n % i == 0) { n /= i; t *= i; } }
|
||
}
|
||
return n > 1 ? ret * (n - 1) : ret;
|
||
}
|
||
//欧拉函数筛 O(nloglogn)
|
||
const int N = 10000000; //~400ms
|
||
int phi[N] = {0, 1};
|
||
void getPhi() {
|
||
for (int i = 2; i < N; i++) {
|
||
if (!phi[i]) {
|
||
for (int j = i; j < N; j += i) {
|
||
if (!phi[j]) { phi[j] = j; } phi[j] -= phi[j] / i;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
//素数 + 欧拉函数筛 O(n)
|
||
const int N = 10000000; //~150ms
|
||
int prime[N >> 3], phi[N] = {0, 1}; bitset<N> isprime;
|
||
void getPrimePhi() {
|
||
isprime.set(); isprime[0] = isprime[1] = false;
|
||
for (int i = 2; i < N; i++) {
|
||
if (isprime[i]) { prime[++prime[0]] = i; phi[i] = i - 1; }
|
||
for (int j = 1, k; j <= prime[0] && prime[j] * i < N; j++) {
|
||
isprime[k = prime[j] * i] = false;
|
||
if (i % prime[j] == 0) { phi[k] = phi[i] * prime[j]; break; }
|
||
phi[k] = phi[i] * (prime[j] - 1);
|
||
}
|
||
}
|
||
}
|
||
//素数 + 莫比乌斯函数筛 O(n)
|
||
const int N = 10000000; //150ms
|
||
int prime[N >> 3], miu[N] = {0, 1}; bitset<N> isprime;
|
||
void getPrimeMiu() {
|
||
isprime.set(); isprime[0] = isprime[1] = false;
|
||
for (int i = 2; i < N; i++) {
|
||
if (isprime[i]) { prime[++prime[0]] = i; miu[i] = -1; }
|
||
for (int j = 1, k; j <= prime[0] && prime[j] * i < N; j++) {
|
||
isprime[k = prime[j] * i] = false;
|
||
if (i % prime[j] == 0) { miu[k] = 0; break; }
|
||
miu[k] = -miu[i];
|
||
}
|
||
}
|
||
}
|
||
//素数 + 欧拉函数 + 莫比乌斯函数筛 O(n)
|
||
const int N = 10000000; //~230ms
|
||
int prime[N >> 3], phi[N] = {0, 1}, miu[N] = {0, 1}; bitset<N> isnprime;
|
||
void getPrimePhiMiu() {
|
||
for (int i = 2; i < N; i++) {
|
||
if (!isnprime[i]) { prime[++prime[0]] = i; phi[i] = i - 1; miu[i] = -1; }
|
||
for (int j = 1, k; j <= prime[0] && prime[j] * i < N; j++) {
|
||
isnprime[k = prime[j] * i] = true;
|
||
if (i % prime[j] == 0) { phi[k] = phi[i] * prime[j]; miu[k] = 0; break; }
|
||
phi[k] = phi[i] * (prime[j] - 1); miu[k] = -miu[i];
|
||
}
|
||
}
|
||
}
|
||
//素数 + 约数个数筛 O(n)
|
||
const int N = 10000000; //~200ms
|
||
bitset<N> isprime;
|
||
int prime[N >> 3], faccnt[N] = {0, 1}, d[N]; //d[i]表示i的最小质因子的幂次
|
||
void getPrimeFaccnt() {
|
||
isprime.set(); isprime[0] = isprime[1] = false;
|
||
for (int i = 2; i < N; i++) {
|
||
if (isprime[i]) { prime[++prime[0]] = i; faccnt[i] = 2; d[i] = 1; }
|
||
for (int j = 1, k; j <= prime[0] && prime[j] * i < N; j++) {
|
||
isprime[k = prime[j] * i] = false;
|
||
if (i % prime[j] == 0) {
|
||
faccnt[k] = faccnt[i] / (d[i] + 1) * (d[i] + 2); d[k] = d[i] + 1; break;
|
||
}
|
||
faccnt[k] = faccnt[i] << 1; d[k] = 1;
|
||
}
|
||
}
|
||
}
|
||
//A^B的约数之和为:
|
||
//sum = [1+p1+p1^2+...+p1^(a1*B)]*...*[1+pn+pn^2+...+pn^(an*B)].
|
||
//等比数列求和 1+a+a^2+...+a^b
|
||
ll sumPow(ll a, ll b, ll m) {
|
||
ll r = 1; a %= m;
|
||
for (ll t = 1; b; b >>= 1) {
|
||
if (b & 1) { r = (r * a + t) % m; }
|
||
t = t * (a + 1) % m;
|
||
a = a * a % m;
|
||
}
|
||
return r;
|
||
}
|
||
//求逆元(ax = 1(mod m)的x值)
|
||
//扩展欧几里得(求ax + by = gcd(a, b)的解), 求出的x为a对b的模逆元
|
||
ll exgcd(ll a, ll b, ll &x, ll &y) {
|
||
if (b == 0) { x = 1; y = 0; return a; }
|
||
ll d = exgcd(b, a % b, y, x); y -= a / b * x; return d;
|
||
}
|
||
//解不定方程ax + by = c 求得的只是其中一组解
|
||
//对于不定整数方程ax + by = c, 若c mod gcd(a, b) = 0, 则该方程存在整数解, 否则不存在整数解
|
||
//在找到ax + by = gcd(a, b)的一组解x0, y0后,可得到ax + by = c的一组解x1 = x0 * (c / gcd(a, b)), y1 = y0 * (c / gcd(a,b))
|
||
//ax + by = c的其他整数解满足:
|
||
//x = x1 + b / gcd(a, b) * t, y = y1 - a / gcd(a, b) * t(其中t为任意整数)
|
||
//求ax + by = c的一组解
|
||
bool linear_equation(int a, int b, int c, int &x, int &y) {
|
||
int d = exgcd(a, b, x, y);
|
||
if (c % d) { return false; }
|
||
int k = c / d; x *= k; y *= k; return true;
|
||
}
|
||
//求ax = b (mod p)循环节内的所有解
|
||
ll ans[N], cnt;
|
||
bool linear_equation(ll a, ll b, ll p) {
|
||
ll x, y, d = exgcd(a, p, x, y); cnt = 0;
|
||
if (b % d) { return false; }
|
||
x = (x % p + p) % p;
|
||
ans[++cnt] = x * (b / d) % (p / d);
|
||
for (int i = 1; i < d; i++) { ans[++cnt] = (ans[1] + i * p / d) % n; }
|
||
return true;
|
||
}
|
||
//线性预处理逆元
|
||
ll Inv[N] = {1, 1};
|
||
void getInv(int m) {
|
||
for (ll i = 2; i < m; i++) { Inv[i] = (m - m / i) * Inv[m % i] % m; }
|
||
}
|
||
//扩展欧几里得求逆元
|
||
ll modReverse(ll a, ll m) {
|
||
ll x, y, d = exgcd(a, m, x, y);
|
||
if (d == 1) { return (x % m + m) % m; } else { return -1; }
|
||
}
|
||
//费马小定理, m为素数, a与m互质
|
||
ll inv(ll a, ll m) { return powMod(a, m - 2, m); }
|
||
//只能求0 < a < m的情况,a和m互质
|
||
ll inv(ll a, ll m) {
|
||
if (a == 1) { return 1; }
|
||
return inv(m % a, m) * (m - m / a) % m;
|
||
}
|
||
//中国剩余定理 求模线性方程组x = a[i] (mod m[i]) m[i]可以不互质
|
||
//[1, n]内解的个数为(n - x) / m1 + (x != 0)
|
||
bool merge(ll a1, ll m1, ll a2, ll m2, ll &a3, ll &m3) {
|
||
ll d = __gcd(m1, m2), c = a2 - a1;
|
||
if (c % d != 0) { return false; }
|
||
c = (c % m2 + m2) % m2 / d; m1 /= d; m2 /= d;
|
||
c = c * inv(m1, m2) % m2 * m1 * d + a1;
|
||
m3 = m1 * m2 * d; a3 = (c % m3 + m3) % m3;
|
||
return true;
|
||
}
|
||
ll CRT(ll a[], ll m[], int k) {
|
||
ll a1 = a[0], m1 = m[0];
|
||
for (int i = 1; i < k; i++) {
|
||
ll a2 = a[i], m2 = m[i], m3, a3;
|
||
if (!merge(a1, m1, a2, m2, a3, m3)) { return -1; }
|
||
a1 = a3; m1 = m3;
|
||
}
|
||
return (a1 % m1 + m1) % m1;
|
||
}
|
||
//模线性方程组 需扩展欧几里得
|
||
//求解方程ax ≡ b (mod m) 相当于求解方程ax + my = b (x, y为整数)
|
||
int m[10], a[10]; //模数为m, 余数为a, X % m = a
|
||
bool solve(int &m0, int &a0, int m, int a) {
|
||
ll y, x, d = exgcd(m0, m, x, y);
|
||
if (abs(a - a0) % d) { return false; }
|
||
x *= (a - a0) / d; x %= m / d;
|
||
a0 = (x * m0 + a0); m0 *= m / d; a0 %= m0;
|
||
if (a0 < 0) { a0 += m0; }
|
||
return true;
|
||
}
|
||
//无解返回false, 有解返回true
|
||
//解的形式最后为a0 + m0 * t (0 <= a0 < m0)
|
||
bool MLES(int &m0, int &a0, int n) { //解为X = a0 + m0 * k
|
||
bool flag = true; m0 = 1; a0 = 0;
|
||
for (int i = 0; i < n; i++) {
|
||
if (!solve(m0, a0, m[i], a[i])) { flag = false; break; }
|
||
}
|
||
return flag;
|
||
}
|
||
//求原根
|
||
ll fac[N];
|
||
ll getRoot(ll n) {
|
||
int cnt = 0;
|
||
for (ll i = 2; i * i < n - 1; i++) { if ((n - 1) % i == 0) { fac[cnt++] = i; fac[cnt++] = (n - 1) / i; } }
|
||
for (int i = 2, j;; i++) {
|
||
for (j = 0; j < cnt; j++) { if (powMod(i, fac[j], n) == 1) { break; } }
|
||
if (j == cnt) { return i; }
|
||
}
|
||
}
|
||
//线性基
|
||
//异或线性基
|
||
//若要查询第k小子集异或和, 则把k写成二进制, 对于是1的第i位, 把从低位到高位第i个不为0的数异或进答案
|
||
//若要判断是否有非空子集的异或和为0, 如果不存在自由基, 那么说明只有空集的异或值为0, 需要高斯消元来判断
|
||
struct XORBase {
|
||
int a[64];
|
||
void clear() { memset(a, 0, sizeof(a)); }
|
||
void ins(ll x) {
|
||
for (int i = 62; i >= 0; i--) {
|
||
if (x & (1 << i)) {
|
||
if (a[i]) { x ^= a[i]; }
|
||
else { a[i] = x; }
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
//查询最大子集异或和
|
||
void query() {
|
||
ll ret = 0;
|
||
for (int i = 62; i >= 0; i--) { ret = max(ret, ret ^ a[i]); }
|
||
return ret;
|
||
}
|
||
};
|
||
//实数线性基
|
||
//ins返回要插入的数是否可以被之前的数线性表示出来, 返回true表示不能, false表示可以
|
||
int m;
|
||
struct Base {
|
||
double a[N][N]; bool v[N];
|
||
void clear() { memset(a, 0, sizeof(a)); memset(v, 0, sizeof(v)); }
|
||
bool ins(double *x) {
|
||
for (int i = 0; i < m; i++) {
|
||
if (fabs(x[i]) > 1e-6) {
|
||
if (v[i]) {
|
||
double t = x[i] / a[i][i];
|
||
for (int j = 0; j < m; j++) { x[j] -= t * a[i][j]; }
|
||
} else {
|
||
v[i] = 1;
|
||
for (int j = 0; j < m; j++) { a[i][j] = x[j]; }
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
};
|
||
//离散对数 大步小步算法 Baby-Step Giant-Step
|
||
//BSGS(a, b, p): 求ax = b (mod p)的最小非负整数解, 若无解则返回 -1
|
||
//rev(a, p): 扩展欧几里得求逆元
|
||
//powMod(base, pow, mod): 快速幂
|
||
//mulMod(a, b, mod): 快速乘(这里用快速乘是为了避免爆long long int, 实际有时可以不用)
|
||
unordered_map<ll, ll> Hash;
|
||
ll BSGS(ll a, ll b, ll p) {
|
||
if (b >= p) { return -1; }
|
||
a %= p, b %= p;
|
||
if (!a && !b) { return 1; } //a和b都是p的倍数的话, 就相当于0^x = 0 (mod p)了, 那么最小非负整数解就是1
|
||
if (!a) { return -1; } //如果a是p的倍数但是b不是, 就相当于0^x = t (mod p), t > 0, 无解
|
||
Hash.clear();
|
||
ll m = ceil(sqrt(p)), tmp = 1 % p; //tmp = a^j
|
||
for (ll j = 0; j < m; j++) { //预处理出a^j mod p的值
|
||
Hash[tmp] = j; tmp = mulMod(tmp, a, p);
|
||
}
|
||
tmp = rev(powMod(a, m, p), p); //tmp = a^(-m)
|
||
for (ll i = 0; i < m; i++) {
|
||
if (Hash.find(b) != Hash.end()) { return i * m + Hash[b]; }
|
||
b = mulMod(b, tmp, p);
|
||
}
|
||
return -1;
|
||
}
|
||
//高斯消元 求线性方程组的解 O(n^3)
|
||
//有equ个方程, var个变元, 增广矩阵行数为equ, 列数为var + 1, 下标从0开始
|
||
int a[N][N], x[N]; //增广矩阵, 解集
|
||
int freex[N], freenum;//自由变元 (多解枚举自由变元可以使用)
|
||
//返回值为-1表示无解, 为0是唯一解, 否则返回自由变元个数
|
||
int Gauss(int equ, int var) {
|
||
int mxrow, col, k; freenum = 0;
|
||
for (k = 0, col = 0; k < equ && col < var; k++, col++) {
|
||
mxrow = k;
|
||
for (int i = k + 1; i < equ; i++) { if (abs(a[i][col]) > abs(a[mxrow][col])) { mxrow = i; } }
|
||
if (a[mxrow][col] == 0) { k--; freex[freenum++] = col; continue; } //自由变元
|
||
if (mxrow != k) { for (int j = col; j <= var; j++) { swap(a[k][j], a[mxrow][j]); } }
|
||
for (int i = k + 1; i < equ; i++) {
|
||
if (a[i][col]) {
|
||
int x = abs(a[i][col]), y = abs(a[k][col]), lcm = x / __gcd(x, y) * y, tx = lcm / x, ty = lcm / y;
|
||
if (a[i][col] * a[k][col] < 0) { ty = -ty; }
|
||
for (int j = col; j <= var; j++) {
|
||
a[i][j] = a[i][j] * tx - a[k][j] * ty; //a[i][j] = (a[i][j] % M + M) % M;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
for (int i = k; i < equ; i++) { if (a[i][col]) { return -1; } } //无解
|
||
if (k < var) { return var - k; } //自由变元个数
|
||
for (int i = var - 1; i >= 0; i--) { //唯一解,回代
|
||
for (int j = i + 1; j < var; j++) {
|
||
if (a[i][j]) { a[i][var] -= a[i][j] * x[j]; /*a[i][var] = (a[i][var] % M + M) % M;*/ }
|
||
}
|
||
//while (a[i][var] % a[i][i]) { a[i][var] += M; }
|
||
x[i] = a[i][var] / a[i][i]; //x[i] = (a[i][var] * inv(a[i][i], M)) % M;
|
||
}
|
||
return 0;
|
||
}
|
||
//高斯消元 (浮点数)
|
||
const double eps = 1e-9;
|
||
const int N = 205;
|
||
double a[N][N], x[N]; //方程的左边的矩阵和等式右边的值, 求解之后x存的就是结果
|
||
int equ, var; //方程数和未知数个数
|
||
//返回0表示无解, 1表示有解
|
||
int Gauss() {
|
||
int i, j, k, col, mxrow;
|
||
for (k = 0, col = 0; k < equ && col < var; k++, col++) {
|
||
mxrow = k;
|
||
for (i = k + 1; i < equ; i++) {
|
||
if (fabs(a[i][col]) > fabs(a[mxrow][col])) { mxrow = i; }
|
||
}
|
||
if (fabs(a[mxrow][col]) < eps) { return 0; }
|
||
if (k != mxrow) {
|
||
for (j = col; j < var; j++) { swap(a[k][j], a[mxrow][j]); }
|
||
swap(x[k], x[mxrow]);
|
||
}
|
||
x[k] /= a[k][col];
|
||
for (j = col + 1; j < var; j++) { a[k][j] /= a[k][col]; }
|
||
a[k][col] = 1;
|
||
for (i = 0; i < equ; i++) {
|
||
if (i != k) {
|
||
x[i] -= x[k] * a[i][k];
|
||
for (j = col + 1; j < var; j++) { a[i][j] -= a[k][j] * a[i][col]; }
|
||
a[i][col] = 0;
|
||
}
|
||
}
|
||
}
|
||
return 1;
|
||
}
|
||
//自适应simpson积分
|
||
//给定一个函数f(x), 求[a, b]区间内f(x)到x轴所形成区域的面积
|
||
double simpson(double l, double r) {return (f(l) + f(r) + 4 * f((l + r) / 2.0)) * (r - l) / 6.0;}
|
||
double rsimpson(double l, double r) {
|
||
double mid = (l + r) / 2.0;
|
||
if (fabs(simpson(l, r) - simpson(l, mid) - simpson(mid, r)) < EPS) {
|
||
return simpson(l, mid) + simpson(mid, r);
|
||
}
|
||
return rsimpson(l, mid) + rsimpson(mid, r);
|
||
}
|
||
//FFT O(nlogn)
|
||
//以下n必须为2的幂, op为1时是求DFT, op为-1时为求IDFT
|
||
typedef complex<double> comp;
|
||
const double PI = acos(-1.0);
|
||
void fft(comp a[], int n, int op) {
|
||
for (int i = 1, j = 0; i < n - 1; i++) {
|
||
for (int s = n; j ^= s >>= 1, ~j & s;);
|
||
if (i < j) { swap(a[i], a[j]); }
|
||
}
|
||
for (int i = 1; i < n; i <<= 1) {
|
||
comp wn(cos(PI / i), op * sin(PI / i));
|
||
for (int j = 0; j < n; j += i << 1) {
|
||
comp w(1, 0);
|
||
for (int k = 0; k < i; k++, w *= wn) {
|
||
comp x = a[j + k], y = w * a[i + j + k];
|
||
a[j + k] = x + y; a[i + j + k] = x - y;
|
||
}
|
||
}
|
||
}
|
||
if (op == -1) { for (int i = 0; i < n; i++) { a[i] = comp(a[i].real() / n, a[i].imag()); } }
|
||
}
|
||
//求高精度乘法 HDU 1402
|
||
comp a[N], b[N];
|
||
char str1[N / 2], str2[N / 2];
|
||
int sum[N];
|
||
int main() {
|
||
while (~scanf("%s%s", str1, str2)) {
|
||
memset(a, 0, sizeof(a)); memset(b, 0, sizeof(b));
|
||
int n = strlen(str1), m = strlen(str2), len = 1;
|
||
while (len < n * 2 || len < m * 2) { len <<= 1; }
|
||
for (int i = 0; i < n; i++) { a[i] = comp(str1[n - 1 - i] - '0', 0); }
|
||
for (int i = 0; i < m; i++) { b[i] = comp(str2[m - 1 - i] - '0', 0); }
|
||
fft(a, len, 1); fft(b, len, 1);
|
||
for (int i = 0; i < len; i++) { a[i] *= b[i]; }
|
||
fft(a, len, -1);
|
||
for (int i = 0; i < len; i++) { sum[i] = (int)(a[i].real() + 0.5); }
|
||
for (int i = 0; i < len; i++) { sum[i + 1] += sum[i] / 10; sum[i] %= 10; }
|
||
len = n + m - 1;
|
||
while (sum[len] <= 0 && len > 0) { len--; }
|
||
for (int i = len; i >= 0; i--) { putchar(sum[i] + '0'); } puts("");
|
||
}
|
||
}
|
||
//NTT O(nlogn)
|
||
//998244353 = 119 * 2^23 + 1, 原根为3; 1004535809 = 479 * 2^21 + 1, 原根为3
|
||
//786433 = 3 * 2^18 + 1, 原根为10; 880803841 = 105 * 2^23 + 1, 原根为26
|
||
//P是素数且N必须是P - 1的因子
|
||
//op为1时是求FNT, op为-1时为求IFNT
|
||
const int P = 998244353, G = 3, N = 262144, K = 17;
|
||
ll g[N + 5], ng[N + 5], Inv[N + 5] = {1, 1};
|
||
void initG() {
|
||
g[K] = powMod(G, (P - 1) / N, P); ng[K] = powMod(g[K], P - 2, P);
|
||
for (int i = K - 1; i >= 0; i--) { g[i] = g[i + 1] * g[i + 1] % P; ng[i] = ng[i + 1] * ng[i + 1] % P; }
|
||
for (ll i = 2; i <= N; i++) { Inv[i] = (P - P / i) * Inv[P % i] % P; }
|
||
}
|
||
void ntt(ll a[], int n, int op) {
|
||
for (int i = 1, j = 0; i < n - 1; i++) {
|
||
for (int s = n; j ^= s >>= 1, ~j & s;);
|
||
if (i < j) { swap(a[i], a[j]); }
|
||
}
|
||
for (int d = 0; (1 << d) < n; d++) {
|
||
int m = 1 << d; ll w0 = op == 1 ? g[d] : ng[d];
|
||
for (int i = 0; i < n; i += m << 1) {
|
||
for (int j = 0, w = 1; j < m; j++, w = w * w0 % P) {
|
||
ll &x = a[i + j + m], &y = a[i + j], t = w * x % P;
|
||
x = y - t; y = y + t;
|
||
if (x < 0) { x += P; } if (y >= P) { y -= P; }
|
||
}
|
||
}
|
||
}
|
||
if (op == -1) { for (int i = 0; i < n; i++) { a[i] = a[i] * Inv[n] % P; } }
|
||
}
|
||
//多项式求逆元 O(nlogn) 即求B(x)满足A(X) * B(x) = 1 (mod x^n), deg(B) <= deg(A)
|
||
void polyInv(ll a[], ll b[], int n) {
|
||
if (n == 1) { b[0] = powMod(a[0], P - 2, P); return; }
|
||
polyInv(a, b, n >> 1);
|
||
int k = 1;
|
||
while (k < n << 1) { k <<= 1; }
|
||
for (int i = 0; i < n; i++) { tmp[i] = a[i]; }
|
||
for (int i = n; i < k; i++) { tmp[i] = b[i] = 0; }
|
||
ntt(tmp, k, 1); ntt(b, k, 1);
|
||
for (int i = 0; i < k; i++) {
|
||
b[i] = b[i] * (2 - tmp[i] * b[i] % P) % P;
|
||
if (b[i] < 0) { b[i] += P; }
|
||
}
|
||
ntt(b, k, -1);
|
||
for (int i = n; i < k; i++) { b[i] = 0; }
|
||
}
|
||
//多项式除法 O(nlogn) 即求D(x)和R(x)满足A(x) = D(x) * B(x) + R(x), deg(D) <= deg(A) - deg(B), deg(R) < deg(B)
|
||
ll a0[N], b0[N];
|
||
void polyDiv(ll a[], int n, ll b[], int m, ll d[], ll r[]) {
|
||
int k = 1, t = n - m + 1;
|
||
while (k < t << 1) { k <<= 1; }
|
||
for (int i = 0; i < k; i++) { a0[i] = b0[i] = 0; }
|
||
for (int i = 0; i < m; i++) { a0[i] = b[m - i - 1]; }
|
||
polyInv(a0, b0, t);
|
||
for (int i = t; i < k; i++) { b0[i] = 0; }
|
||
for (int i = 0; i < t; i++) { a0[i] = a[n - i - 1]; }
|
||
for (int i = t; i < k; i++) { a0[i] = 0; }
|
||
ntt(b0, k, 1); ntt(a0, k, 1);
|
||
for (int i = 0; i < k; i++) { a0[i] = a0[i] * b0[i] % P; }
|
||
ntt(a0, k, -1);
|
||
reverse(a0, a0 + t);
|
||
for (int i = 0; i < t; i++) { d[i] = a0[i]; }
|
||
for (k = 1; k < n << 1; k <<= 1);
|
||
for (int i = t; i < k; i++) { a0[i] = 0; }
|
||
for (int i = 0; i < m; i++) { b0[i] = b[i]; }
|
||
for (int i = m; i < k; i++) { b0[i] = 0; }
|
||
ntt(a0, k, 1); ntt(b0, k, 1);
|
||
for (int i = 0; i < k; i++) { a0[i] = a0[i] * b0[i] % P; }
|
||
ntt(a0, k, -1);
|
||
for (int i = 0; i < m; i++) { r[i] = (a[i] - a0[i]) % P; }
|
||
for (int i = m; i < k; i++) { r[i] = 0; }
|
||
}
|
||
//多项式求对数函数 O(nlogn) a[0] = 1
|
||
void polyLn(ll a[], ll b[], int n) {
|
||
polyInv(a, tmp2, n);
|
||
int k = 1;
|
||
while (k < n << 1) { k <<= 1; }
|
||
for (int i = 0; i < n - 1; i++) { b[i] = a[i + 1] * (i + 1) % P; }
|
||
for (int i = n - 1; i < k; i++) { b[i] = 0; }
|
||
ntt(b, k, 1); ntt(tmp2, k, 1);
|
||
for (int i = 0; i < k; i++) { b[i] = b[i] * tmp2[i] % P; }
|
||
ntt(b, k, -1);
|
||
for (int i = n - 1; i >= 0; i--) { b[i] = b[i - 1] * Inv[i] % P; } b[0] = 0;
|
||
}
|
||
//多项式求指数函数 O(nlogn) a[0] = 0
|
||
void polyExp(ll a[], ll b[], int n) {
|
||
if (n == 1) { b[0] = 1; return; }
|
||
polyExp(a, b, n >> 1); polyLn(b, tmp, n);
|
||
int k = 1;
|
||
while (k < n << 1) { k <<= 1; }
|
||
for (int i = 0; i < n; i++) { tmp[i] -= a[i]; if (tmp[i] < 0) { tmp[i] += P; } }
|
||
if (++tmp[0] == P) { tmp[0] = 0; }
|
||
for (int i = n; i < k; i++) { tmp[i] = b[i] = 0; }
|
||
ntt(tmp, k, 1); ntt(b, k, 1);
|
||
for (int i = 0; i < k; i++) { b[i] = b[i] * tmp[i] % P; }
|
||
ntt(b, k, -1);
|
||
for (int i = n; i < k; i++) { b[i] = 0; }
|
||
}
|
||
//多项式求平方根 O(nlogn) a[0] = 1
|
||
void polySqrt(ll a[], ll b[], int n) {
|
||
if (n == 1) { b[0] = 1; return; }
|
||
polySqrt(a, b, n >> 1); polyInv(b, tmp2, n);
|
||
int k = 1;
|
||
while (k < n << 1) { k <<= 1; }
|
||
for (int i = 0; i < n; i++) { tmp[i] = a[i]; }
|
||
for (int i = n; i < k; i++) { tmp[i] = b[i] = 0; }
|
||
ntt(tmp, k, 1); ntt(b, k, 1); ntt(tmp2, k, 1);
|
||
for (int i = 0; i < k; i++) { b[i] = (b[i] * b[i] + tmp[i]) % P * Inv[2] % P * tmp2[i] % P; }
|
||
ntt(b, k, -1);
|
||
for (int i = n; i < k; i++) { b[i] = 0; }
|
||
}
|
||
//快速沃尔什变换 即求C[i] = sum{j ? k = i}(A[j] * B[k]) ?为任一二元逻辑位运算
|
||
void fwt(ll a[], int n) {
|
||
for (int d = 1; d < n; d <<= 1) {
|
||
for (int i = 0, m = d << 1; i < n; i += m) {
|
||
for (int j = 0; j < d; j++) {
|
||
ll x = a[i + j], y = a[i + j + d];
|
||
//xor: a[i + j] = x + y; a[i + j + d] = x - y;
|
||
//and: a[i + j] = x + y;
|
||
//or: a[i + j + d] = x + y;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
void ufwt(ll a[], int n) {
|
||
for (int d = 1; d < n; d <<= 1) {
|
||
for (int i = 0, m = d << 1; i < n; i += m) {
|
||
for (int j = 0; j < d; j++) {
|
||
ll x = a[i + j], y = a[i + j + d];
|
||
//xor: a[i + j] = (x + y) >> 1; a[i + j + d] = (x - y) >> 1;
|
||
//and: a[i + j] = x - y;
|
||
//or: a[i + j + d] = y - x;
|
||
}
|
||
}
|
||
}
|
||
}
|