Number 数论

Number 数论

素数筛

欧拉筛

对if(i % prime[j] == 0) break;的解释

当i % prime[j] == 0时有 i = k * prime[j]; 若j++有 i * prime[j + 1] = k * prime[j] * prime[j + 1] 也是prime[j]的因子,导致重复筛

const int maxn = 1e7 + 8;
vector<int > prime(maxn, 0);
bitset<maxn> vis(0);
void getPrime() {
	for(int i = 2;i < maxn;i++) {
		if(vis[i] == 0) prime[++prime[0]] = i;
		for(int j = 1;j <= prime[0];j++) {
			if(i * prime[j] >= maxn) break;
			vis[i * prime[j]] = 1;
			if(i % prime[j] == 0) break;
		}
	}
}

埃式筛

void Prime(){
    vector<int > vis(maxn, 0); //初始化都是素数
    vis[0] = vis[1] = 1;    //0 和 1不是素数
    for (int i = 2; i <= maxn; i++) {
        if (!vis[i]) {      //如果i是素数,让i的所有倍数都不是素数
            for (int j = i * i; j <= maxn; j += i) { 
                vis[j] = 1;
            }
        }
    }
}

欧拉函数

​ 用处:1:求1-n内与n互质的数量

​ 2:求合数的逆元

​ 3:欧拉降幂

int phi(int x) {
	int ans = x;
	for(int i = 2;i * i <= x;i++) {
		if(x % i == 0) {
			ans = ans / i * (i - 1);
			while(x % i == 0) x /= i;
		}
	}
	if(x > 1) ans = ans / x * (x - 1);
	return ans;
}

线性筛欧拉函数

const int maxn = 100005;
vector<int > prime(maxn, 0), vis(maxn, 0), phi(maxn, 0);
void getPrime() {
    phi[1] = 1;
	for(int i = 2;i < maxn;i++) {
		if(vis[i] == 0) prime[++prime[0]] = i, phi[i] = i - 1;
		for(int j = 1;j <= prime[0];j++) {
			if(i * prime[j] >= maxn) break;
			vis[i * prime[j]] = 1;
			if(i % prime[j] != 0) phi[i * prime[j]] = phi[i] * (prime[j] - 1);
            //对于任意的a,b若gcd(a, b) == 1 -> phi(a * b) = phi(a) * phi(b)
			else {
                phi[i * prime[j]] = phi[i] * prime[j];
                break;
            }
		}
	}
}

任意区间素数打表

const int M=1e6+5,N=(1<<16);
int prime[N+5],is[N+5],tot;
void getPrime(){
    is[1]=1;//mmpaaaaaaaaaaaaaaaa
    for(int i=2;i<=N;++i){
        if(!is[i]) prime[++tot]=i;
        for(int j=1;j<=tot&&(ll)i*prime[j]<=N;++j){
            is[i*prime[j]]=1;
            if(i%prime[j]==0) break;
        }
    }
}
int issp[M];
int main(){
    getPrime();
    int T,cas=0;scanf("%d",&T);
    while(T--){
        m(issp,0);
        int a,b;scanf("%d%d",&a,&b);
        if(a<=N&&b<=N) {
            int ans=0;
            for(int i=a;i<=b;++i) if(!is[i]) ++ans;
            printf("Case %d: %d\n",++cas,ans);
            continue;
        }
        int ans=0;
        if(a<=N) {
            for(int i=a;i<=N;++i) if(!is[i]) ++ans;
            a=N+1;
        }
        for(int i=1;i<=tot;++i) {
            ll l=a/prime[i]*prime[i];//左端点l.
            if(l<a) l+=prime[i];
            if(l==prime[i]) l+=prime[i];
            for(ll j=l;j<=b;j+=prime[i]) issp[j-a]=1;
        }
        for(int j=a;j<=b;++j) if(!issp[j-a]) ++ans;
        printf("Case %d: %d\n",++cas,ans);
    }
}

大数素数测试

Miller_Rabin

#include <bits/stdc++.h>

using namespace std;
using ll = __int128;

const int S = 8; //随机算法判定次数一般 8~10 就够了
// 计算 ret = (a*b)%c a,b,c < 2^63
__int128 mult_mod(__int128 a, __int128 b, __int128 c) {
    a %= c;
    b %= c;
    __int128 ret = 0;
    __int128 tmp = a;

    while (b) {
        if (b & 1) {
            ret += tmp;

            if (ret > c)
                ret -= c;//直接取模慢很多
        }

        tmp <<= 1;

        if (tmp > c)
            tmp -= c;

        b >>= 1;
    }

    return ret;
}
// 计算 ret = (a^n)%mod
__int128 pow_mod(__int128 a, __int128 n, __int128 mod) {
    __int128 ret = 1;
    __int128 temp = a % mod;

    while (n) {
        if (n & 1)
            ret = mult_mod(ret, temp, mod);

        temp = mult_mod(temp, temp, mod);
        n >>= 1;
    }

    return ret;
}
bool check(__int128 a, __int128 n, __int128 x, __int128 t) {
    __int128 ret = pow_mod(a, x, n);
    __int128 last = ret;

    for (int i = 1; i <= t; i++) {
        ret = mult_mod(ret, ret, n);

        if (ret == 1 && last != 1 && last != n - 1)
            return true;//合数

        last = ret;
    }

    if (ret != 1)
        return true;
    else
        return false;
}
//**************************************************
// Miller_Rabin 算法
// 是素数返回 true,(可能是伪素数)
// 不是素数返回 false
//**************************************************
bool MR(__int128 n) {
    if (n < 2)
        return false;

    if (n == 2)
        return true;

    if ((n & 1) == 0)
        return false;//偶数

    __int128 x = n - 1;
    __int128 t = 0;

    while ((x & 1) == 0) {
        x >>= 1;
        t++;
    }

    srand(time(NULL));

    for (int i = 0; i < S; i++) {
        __int128 a = rand() % (n - 1) + 1;

        if (check(a, n, x, t))
            return false;
    }

    return true;
}
inline __int128 read() {
    __int128 x = 0, f = 1;
    char ch = getchar();

    while (ch < '0' || ch > '9') {
        if (ch == '-')
            f = -1;

        ch = getchar();
    }

    while (ch >= '0' && ch <= '9') {
        x = x * 10 + ch - '0';
        ch = getchar();
    }

    return x * f;
}
int main() {
    __int128 n = read();

    if (MR(n))
        puts("Yes");
    else
        puts("No");

    return 0;
}

Miller_Rabin(Easy ver)

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

ll mul(ll a, ll b, ll p) {
	return (__int128)a * b % p;
}

ll qp(ll x, ll y, ll p) {
	ll z = 1;
	for (; y; y >>= 1, x = mul(x, x, p)) {
		if (y & 1) z = mul(z, x, p);
	}
	return z;
}

bool MR(ll x, ll b) {
	for (ll k = x - 1; k; k >>= 1) {
		ll cur = qp(b, k, x);
		if (cur != 1 && cur != x - 1) return 0;
		if (k & 1 || cur == x - 1) return 1;
	}
	return true;
}

bool test(ll x) {
	if (x == 1) return 0;
	static ll p[] = {2, 3, 5, 7, 17, 19, 61};
	for (ll y : p) {
		if (x == y) return 1;
		if (!MR(x, y)) return 0;
	}
	return 1;
}

int main() {
	ll n;
	while (scanf("%lld", &n) != EOF) {
		puts(test(n) ? "Y" : "N");
	}
	return 0;
}

大数分解

逆元

Exgcd求a在b意义下的逆元

i f ( g c d ( a , b ) = = 1 ) if(gcd(a, b)==1) if(gcd(a,b)==1)

int exgcd(int a, int b, int &x, int &y) {
	if(b == 0) {
		x = 1;
		y = 0;
		return a;
	}
	else {
		int gcd = exgcd(b, a % b, x, y);
		int t = x;
		x = y;
		y = t - a / b * y;
		return gcd;
	}
}
int getInv(int a, int b){
	int x, y;
	exgcd(a, b, x, y);
	return (x + b) % b;
}

费马小定理求a在mod p意义下的逆元(p是素数)

a ∗ a p − 2 = 1 ( m o d p ) a * a^{p - 2} = 1{(modp)} a∗ap−2=1(modp)

int qpow(int a, int b, int mod) {
	int ans = 1;
	while(b) {
		if(b & 1) ans = ans * a % mod;
		b >>= 1, a = a * a % mod;
	}
	return ans;
}
int getInv(int x, int mod) {
	return qpow(x, mod - 2, mod);
}

费马小定理求a在mod p意义下的逆元(p不是素数)

a ∗ a p h i ( p ) − 1 = 1 ( m o d p ) a*a^{phi(p) - 1} = 1(modp) a∗aphi(p)−1=1(modp)

int qpow(int a, int b, int mod) {
	int ans = 1;
	while(b) {
		if(b & 1) ans = ans * a % mod;
		b >>= 1, a = a * a % mod;
	}
	return ans;
}
int phi(int x) {
	int ans = x;
	for(int i = 2;i * i <= x;i++) {
		if(x % i == 0) {
			ans = ans * (i - 1) / i;
			while(x % i == 0) x /= i;
		}
	}
	if(x > 1) ans = ans * (x - 1) / x;
	return ans;
}
int getInv(int x, int mod) {
	return qpow(x, phi(mod) - 1, mod);
}

O(n)求逆元

vector<ll> inv(3000006, 0);
void liner_inv(int n, int p) {
	inv[1] = 1;
	for(int i = 2;i <= n;i++) inv[i] = 1ll * (p - p / i) * inv[p % i] % p;
}

O(n + log(mod))求任意n个数的逆元

const ll mod  = 1e9 + 7;
const ll p    = 998244353;
const ll maxn = 1e5 + 7;

vector<ll> a(maxn, 0), pre(maxn, 1), pre_inv(maxn, 0), inv(maxn, 0);
//		   数组元素    前缀积		 前缀积的逆元	   每个数的逆元

ll qpow(ll a, ll b) {
	ll ret = 1;
	while(b) {
		if(b & 1) ret = ret * a % mod;
		b >>= 1, a = a * a % mod;
	}
	return ret;
}

void solve(int n) {//数组长度参数
	for(int i = 1;i <= n;i++) cin >> a[i];
	for(int i = 1;i <= n;i++) pre[i] = pre[i - 1] * a[i] % mod;
	pre_inv[n] = qpow(pre[n], mod - 2);
	for(int i = n;i >= 1;i--) pre_inv[i - 1] = pre_inv[i] * a[i] % mod;
	for(int i = 1;i <= n;i++) inv[i] = pre_inv[i] * pre[i - 1] % mod;
}

小数循环节

int c(int tmp) {
    while(tmp % 2 == 0) tmp /= 2;
	while(tmp % 5 == 0) tmp /= 5;
	int len = 0, e = 1;
	if(tmp == 1) return -1;
	while(1) {
		e = e * 10 % tmp;
		if(e == 1) break;
		len++;
	}
	return len;
}

组合数

C n m = n ! m ! ∗ ( n − m ) ! C_n^m = \frac{n!}{m!*(n - m)!} Cnm​=m!∗(n−m)!n!​

正常版本

const int maxn = 2e5 + 7;
vector<ll> fac(maxn, 1);

void init(ll p) {//if module is different
	for(ll i = 1;i <= 200000;i++) fac[i] = fac[i - 1] * i % p;
}

ll qpow(ll a, ll b, ll p) {
	ll ret = 1;
	while(b) {
		if(b & 1) ret = ret * a % p;
		b >>= 1;
		a = a * a % p;
	}
	return ret;
}

ll getInv(ll x, ll p) {
	if(x == 1) return 1;
	return qpow(x, p - 2, p);
}

ll c(ll n, ll m, ll p) {
	if(!m) return 1;
	if(m > n) return 0;
	return fac[n] * getInv(fac[m], p) % p * getInv(fac[n - m], p) % p;
}

Mint版本

constexpr int mod = 1000000007;
constexpr int maxn = 1e5 + 6;
// assume -mod <= x < 2mod
int norm(int x) {if(x < 0) x += mod; if (x >= mod) x -= mod; return x; }
template<class T>T power(T a, ll b){T res = 1;for (; b; b /= 2, a *= a)if (b & 1)res *= a;return res;}
struct Mint {
    int x;Mint(int x = 0) : x(norm(x)){}
    int val() const {return x;}
    Mint operator-() const {return Mint(norm(mod - x));}
    Mint inv() const {assert(x != 0);return power(*this, mod - 2);}
    Mint &operator*=(const Mint &rhs) { x = ll(x) * rhs.x % mod; return *this;}
    Mint &operator+=(const Mint &rhs) { x = norm(x + rhs.x); return *this;}
    Mint &operator-=(const Mint &rhs) { x = norm(x - rhs.x); return *this;}
    Mint &operator/=(const Mint &rhs) {return *this *= rhs.inv();}
    friend Mint operator*(const Mint &lhs, const Mint &rhs) {Mint res = lhs; res *= rhs; return res;}
    friend Mint operator+(const Mint &lhs, const Mint &rhs) {Mint res = lhs; res += rhs; return res;}
    friend Mint operator-(const Mint &lhs, const Mint &rhs) {Mint res = lhs; res -= rhs; return res;}
    friend Mint operator/(const Mint &lhs, const Mint &rhs) {Mint res = lhs; res /= rhs; return res;}
};

vector<Mint> fac(maxn, 1);

void init() {
	for(ll i = 1;i < maxn;i++) fac[i] = fac[i - 1] * i;
}

Mint c(ll n, ll m) {
	return fac[n] / fac[m] / fac[n - m];
}

容斥原理

CRT

using ll = long long;

ll qpow(ll a, ll b, ll mod) {
	ll ret = 1;
	while(b) {
		if(b & 1) ret = ret * a % mod;
		b >>= 1;
		a = a * a % mod;
	}
	return ret;
}

ll getInv(ll x, ll mod) {
	return qpow(x, mod - 2, mod);
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

	ll n, mul = 1, sum = 0;
	cin >> n;
	vector<ll> a(n + 1, 0), mu(n + 1, 0);
	for(int i = 1;i <= n;i++) cin >> a[i] >> mu[i];
	for(int i = 1;i <= n;i++) mul *= a[i];
	for(int i = 1;i <= n;i++) {
		ll lcm = mul / a[i];
		ll val = getInv(lcm, a[i]) * mu[i] * lcm;
		sum += val;
	}
	cout << sum % mul << '\n';

    return 0;
}

Lucas/ExLucas

Lucas

const int maxn = 2e5 + 7;
vector<ll> fac(maxn, 1);

void init(ll p) {//if module is different
	for(ll i = 1;i <= 200000;i++) fac[i] = fac[i - 1] * i % p;
}

ll qpow(ll a, ll b, ll p) {
	ll ret = 1;
	while(b) {
		if(b & 1) ret = ret * a % p;
		b >>= 1;
		a = a * a % p;
	}
	return ret;
}

ll getInv(ll x, ll p) {
	if(x == 1) return 1;
	return qpow(x, p - 2, p);
}

ll c(ll n, ll m, ll p) {
	if(!m) return 1;
	if(m > n) return 0;
	return fac[n] * getInv(fac[m], p) % p * getInv(fac[n - m], p) % p;
}

ll lucas(ll n, ll m, ll p) {
	if(n == 0) return 1;
	return lucas(n / p, m / p, p) * c(n % p, m % p, p) % p;
}

Mint version

constexpr int mod = 1000000007;
const int maxn = 1e5 + 6;
// assume -mod <= x < 2mod
int norm(int x) {if(x < 0) x += mod; if (x >= mod) x -= mod; return x; }
template<class T>T power(T a, ll b){T res = 1;for (; b; b /= 2, a *= a)if (b & 1)res *= a;return res;}
struct Mint {
    int x;Mint(int x = 0) : x(norm(x)){}
    int val() const {return x;}
    Mint operator-() const {return Mint(norm(mod - x));}
    Mint inv() const {assert(x != 0);return power(*this, mod - 2);}
    Mint &operator*=(const Mint &rhs) { x = ll(x) * rhs.x % mod; return *this;}
    Mint &operator+=(const Mint &rhs) { x = norm(x + rhs.x); return *this;}
    Mint &operator-=(const Mint &rhs) { x = norm(x - rhs.x); return *this;}
    Mint &operator/=(const Mint &rhs) {return *this *= rhs.inv();}
    friend Mint operator*(const Mint &lhs, const Mint &rhs) {Mint res = lhs; res *= rhs; return res;}
    friend Mint operator+(const Mint &lhs, const Mint &rhs) {Mint res = lhs; res += rhs; return res;}
    friend Mint operator-(const Mint &lhs, const Mint &rhs) {Mint res = lhs; res -= rhs; return res;}
    friend Mint operator/(const Mint &lhs, const Mint &rhs) {Mint res = lhs; res /= rhs; return res;}
};

vector<Mint> fac(maxn, 1);

void init() {
	for(ll i = 1;i < maxn;i++) fac[i] = fac[i - 1] * i;
}

Mint c(ll n, ll m) {
	return fac[n] / fac[m] / fac[n - m];
}

Mint lucas(ll n, ll m) {
	if(m == 0) return 1;
	if(n == 0) return 1;
	if(n < mod && m < mod) return c(n, m);
	return lucas(n / mod, m / mod) * c(n % mod, m % mod);
}

Gcd

Exgcd

int exgcd(int a, int b, int &x, int &y) {
	if(b == 0) {
		x = 1;
		y = 0;
		return a;
	}
	else {
		int gcd = exgcd(b, a % b, x, y);
		int t = x;
		x = y;
		y = t - a / b * y;
		return gcd;
	}
}

矩阵快速幂

实例:求斐波那契数列的第n项

$$
\begin{bmatrix}
{}&{}&{}&{}\
{}&{}&{}&{}\
{}&{}&{}&{}\
{}&{}&{}&{}\
\end{bmatrix}

\begin{bmatrix}
{}&{}&{}\
{}&{}&{}\
{}&{}&{}\
\end{bmatrix}

\begin{bmatrix}
{}&{}\
{}&{}\
\end{bmatrix}
$$

$$
\begin{bmatrix}
{f_{}}&{f_{}}&{f_{}}&{f_{}}\
{f_{}}&{f_{}}&{f_{}}&{f_{}}\
{f_{}}&{f_{}}&{f_{}}&{f_{}}\
{f_{}}&{f_{}}&{f_{}}&{f_{}}\
\end{bmatrix}

\begin{bmatrix}
{f_{}}&{f_{}}&{f_{}}\
{f_{}}&{f_{}}&{f_{}}\
{f_{}}&{f_{}}&{f_{}}\
\end{bmatrix}

\begin{bmatrix}
{f_{}}&{f_{}}\
{f_{}}&{f_{}}\
\end{bmatrix}
$$

$$
\begin{bmatrix}
{f_{}}\
{f_{}}\
{f_{}}\
{f_{}}\
\end{bmatrix}

\begin{bmatrix}
{f_{}}\
{f_{}}\
{f_{}}\
\end{bmatrix}

\begin{bmatrix}
{f_{}}\
{f_{}}\
\end{bmatrix}
$$

$$
f_{i} = a*f_{i - 1} + i:
\begin{bmatrix}
{a}&{1}&{0}\
{0}&{1}&{1}\
{0}&{0}&{1}\
\end{bmatrix}
\cdot
\begin{bmatrix}
{f_{i-1}}\
{{i}}\
{{1}}\
\end{bmatrix}

\begin{bmatrix}
{f_{i}}\
{{i+1}}\
{{1}}\
\end{bmatrix}
$$

$$
f_{i} = f_{i - 1} + f_{i - 2}:
\begin{bmatrix}
{1}&{1}\
{1}&{0}\
\end{bmatrix}
\cdot
\begin{bmatrix}
{f_{n-1}}\
{f_{n-2}}\
\end{bmatrix}

\begin{bmatrix}
{f_{n}}\
{f_{n-1}}\
\end{bmatrix}
$$

#include<bits/stdc++.h>

using namespace std;
using ll = long long;

int n_;       //Size of Matrix
const ll  p = 1e9 + 7;
const int N = 10;

struct matrix { 
	ll a[N][N]{};

	matrix init() {		//to E
		matrix E;
		for(register int i = 0;i < n_;i++) E.a[i][i] = 1;
		return E;
	}
	
	matrix f1_() {		//f(n) = f(n - 1) + f(n - 2),  f[n] = qpow(A, n - 2);
		matrix ret;
		ret.a[0][0] = 1, ret.a[0][1] = 1;
		ret.a[1][0] = 1, ret.a[1][1] = 0;
		return ret;
	}

	matrix f2_() {		//f(n) = f(n - 1) + f(n - 2) + f(n - 3);
		matrix ret;
		ret.a[0][0] = 1, ret.a[0][1] = 1, ret.a[0][2] = 1;
		ret.a[1][0] = 1, ret.a[1][1] = 0, ret.a[1][2] = 0;
		ret.a[2][0] = 0, ret.a[2][1] = 1, ret.a[2][2] = 0;
		return ret;
	}

	matrix f3_() {
		matrix ret;
		//to construct ...
		return ret;
	}

	matrix operator * (const matrix& b) {
		matrix ret;
		for(register int i = 0;i < n_;i++) 
			for(register int j = 0;j < n_;j++) 
				for(register int k = 0;k < n_;k++) 
					ret.a[i][j] = (ret.a[i][j] + a[i][k] * b.a[k][j]) % p;
		return ret;
	}
	matrix qpow(matrix a, ll b) {
		matrix ans = init();
		while(b) {
			if(b & 1) ans = ans * a;
			b >>= 1,  a = a * a;
		}
		return ans;
	}
	void show() {
		for(register int i = 0;i < n_;i++) 
			for(register int j = 0;j < n_;j++) 
				cout << a[i][j] << " \n"[j == n_ - 1];
		return ;
	}
};

ll qpow_(ll a, ll b, ll mod) {
	ll ret = 1;
	while(b){
		if(b & 1) ret = ret * a % mod;
		b >>= 1, a = a * a % mod;
	}
	return ret;
}

void Fib_n() {
	int n; cin >> n;
	if(n == 1 || n == 2) {
		cout << 1 << '\n';
		return ;
	}
	matrix f = f.f1_();
	n_ = 2;
	f = f.qpow(f, n - 2);
	cout << f.a[0][0] + f.a[0][1] << '\n';
}

int main() {
	Fib_n();

    return 0;
}

约瑟夫环

FFT

const int MAXN = 1e6 + 10;
const double Pi = acos(-1.0);
struct complex{
	double x, y;
	complex (double xx = 0, double yy = 0) {x = xx, y = yy;}
}a[MAXN], b[MAXN];
complex operator + (complex a, complex b) { return complex(a.x + b.x , a.y + b.y);}
complex operator - (complex a, complex b) { return complex(a.x - b.x , a.y - b.y);}
complex operator * (complex a, complex b) { return complex(a.x * b.x - a.y * b.y , a.x * b.y + a.y * b.x);} 
int l, r[MAXN], ans[MAXN];
int limit = 1;
void fft(complex *A, int type) {
	for(int i = 0; i < limit; i++) if (i < r[i]) swap(A[i], A[r[i]]); 
	for (int mid = 1; mid < limit; mid <<= 1) { 
		complex Wn( cos(Pi / mid) , type * sin(Pi / mid) ); 
		for (int R = mid << 1, j = 0; j < limit; j += R) { 
			complex w(1, 0);
			for (int k = 0; k < mid; k++, w = w * Wn) { 
				complex x = A[j + k], y = w * A[j + mid + k]; 
				A[j + k] = x + y;
				A[j + mid + k] = x - y;
			}
		}
	}
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	string aa, bb;
	cin >> aa >> bb;
	int n = aa.size(), m = bb.size();
	for (int i = 0; i < n; i++) a[i].x = aa[i] ^ 0x30;
	for (int i = 0; i < m; i++) b[i].x = bb[i] ^ 0x30;
	while (limit <= n + m) limit <<= 1, l++;
	for (int i = 0; i < limit; i++) r[i] = ( r[i >> 1] >> 1 ) | ( (i & 1) << (l - 1));
	fft(a, 1);
	fft(b, 1);
	for (int i = 0; i <= limit; i++) a[i] = a[i] * b[i];
	fft(a, -1);
	for (int i = 0; i <= n + m; i++) ans[i] = (int)(a[i].x / limit + 0.5);
	for(int i = n + m;i >= 1;i--) ans[i - 1] += ans[i] / 10, ans[i] %= 10;
	for(int i = 0;i <= n + m - 2;i++) cout << ans[i]; cout << '\n';
}

NTT

#include <bits/stdc++.h>

using namespace std;

constexpr int P = 998244353;
vector<int> rev, roots{0, 1};

int power(int a, int b) {
	int res = 1;
	for(; b; b >>= 1, a = 1ll * a * a % P) if(b & 1) res = 1ll * res * a % P;
	return res;
}
void dft(vector<int> &a) {
	int n = a.size();
	if(int(rev.size()) != n) {
		int k = __builtin_ctz(n) - 1;
		rev.resize(n);
		for (int i = 0; i < n; ++i) rev[i] = rev[i >> 1] >> 1 | (i & 1) << k;
	}
	for(int i = 0; i < n; ++i) if(rev[i] < i) swap(a[i], a[rev[i]]);
	if(int(roots.size()) < n) {
		int k = __builtin_ctz(roots.size());
		roots.resize(n);
		while((1 << k) < n) {
			int e = power(3, (P - 1) >> (k + 1));
			for(int i = 1 << (k - 1); i < (1 << k); ++i) {
				roots[2 * i] = roots[i];
				roots[2 * i + 1] = 1ll * roots[i] * e % P;
			}
			++k;
		}
	}
	for(int k = 1; k < n; k *= 2) {
		for(int i = 0; i < n; i += 2 * k) {
			for(int j = 0; j < k; ++j) {
				int u = a[i + j];
				int v = 1ll * a[i + j + k] * roots[k + j] % P;
				int x = u + v;
				if(x >= P) x -= P;
				a[i + j] = x;
				x = u - v;
				if(x < 0) x += P;
				a[i + j + k] = x;
			}
		}
	}
}
void idft(vector<int> &a) {
	int n = a.size();
	reverse(a.begin() + 1, a.end());
	dft(a);
	int inv = power(n, P - 2);
	for(int i = 0; i < n; ++i) a[i] = 1ll * a[i] * inv % P;
}
struct Poly {
	vector<int> a;
	Poly(){}
	Poly(int a0) { if (a0) a = {a0}; }
	Poly(const vector<int> &a1) : a(a1) {
		while(!a.empty() && !a.back()) a.pop_back();
	}
	int size() const { return a.size(); }
	int operator[](int idx) const { if (idx < 0 || idx >= size()) return 0; return a[idx]; }
	Poly mulxk(int k) const {
		auto b = a;
		b.insert(b.begin(), k, 0);
		return Poly(b);
	}
	Poly modxk(int k) const {
		k = min(k, size());
		return Poly(vector<int>(a.begin(), a.begin() + k));
	}
	Poly divxk(int k) const {
		if (size() <= k) return Poly();
		return Poly(vector<int>(a.begin() + k, a.end()));
	}
	friend Poly operator+(const Poly a, const Poly &b) {
		vector<int> res(max(a.size(), b.size()));
		for (int i = 0; i < int(res.size()); ++i) {
			res[i] = a[i] + b[i];
			if (res[i] >= P) res[i] -= P;
		}
		return Poly(res);
	}
	friend Poly operator-(const Poly a, const Poly &b) {
		vector<int> res(max(a.size(), b.size()));
		for (int i = 0; i < int(res.size()); ++i) {
			res[i] = a[i] - b[i];
			if (res[i] < 0) res[i] += P;
		}
		return Poly(res);
	}
	friend Poly operator*(Poly a, Poly b) {
		int sz = 1, tot = a.size() + b.size() - 1;
		while (sz < tot) sz *= 2;
		a.a.resize(sz);
		b.a.resize(sz);
		dft(a.a);
		dft(b.a);
		for (int i = 0; i < sz; ++i) a.a[i] = 1ll * a[i] * b[i] % P;
		idft(a.a);
		return Poly(a.a);
	}
	Poly &operator+=(Poly b) { return (*this) = (*this) + b; }
	Poly &operator-=(Poly b) { return (*this) = (*this) - b; }
	Poly &operator*=(Poly b) { return (*this) = (*this) * b; }
	Poly deriv() const {
		if (a.empty()) return Poly();
		vector<int> res(size() - 1);
		for (int i = 0; i < size() - 1; ++i) res[i] = 1ll * (i + 1) * a[i + 1] % P;
		return Poly(res);
	}
	Poly integr() const {
		if(a.empty()) return Poly();
		vector<int> res(size() + 1);
		for (int i = 0; i < size(); ++i) res[i + 1] = 1ll * a[i] * power(i + 1, P - 2) % P;
		return Poly(res);
	}
	Poly inv(int m) const {
		Poly x(power(a[0], P - 2));
		int k = 1;
		while(k < m) {
			k *= 2;
			x = (x * (2 - modxk(k) * x)).modxk(k);
		}
		return x.modxk(m);
	}
	Poly log(int m) const { return (deriv() * inv(m)).integr().modxk(m); }
	Poly exp(int m) const {
		Poly x(1);
		int k = 1;
		while (k < m) {
			k *= 2;
			x = (x * (1 - x.log(k) + modxk(k))).modxk(k);
		}
		return x.modxk(m);
	}
	Poly sqrt(int m) const {
		Poly x(1);
		int k = 1;
		while(k < m) {
			k *= 2;
			x = (x + (modxk(k) * x.inv(k)).modxk(k)) * ((P + 1) / 2);
		}
		return x.modxk(m);
	}
	Poly mulT(Poly b) const {
		if (b.size() == 0) return Poly();
		int n = b.size();
		reverse(b.a.begin(), b.a.end());
		return ((*this) * b).divxk(n - 1);
	}
	vector<int> eval(vector<int> x) const {
		if (size() == 0) return vector<int>(x.size(), 0);
		const int n = max(int(x.size()), size());
		vector<Poly> q(4 * n);
		vector<int> ans(x.size());
		x.resize(n);
		function<void(int, int, int)> build = [&](int p, int l, int r) {
			if (r - l == 1) {
				q[p] = vector<int>{1, (P - x[l]) % P};
			}
			else {
				int m = (l + r) / 2;
				build(2 * p, l, m);
				build(2 * p + 1, m, r);
				q[p] = q[2 * p] * q[2 * p + 1];
			}
		};
		build(1, 0, n);
		function<void(int, int, int, const Poly &)> work = [&](int p, int l, int r, const Poly &num) {
			if (r - l == 1) {
				if (l < int(ans.size()))
					ans[l] = num[0];
			} 
			else {
				int m = (l + r) / 2;
				work(2 * p, l, m, num.mulT(q[2 * p + 1]).modxk(m - l));
				work(2 * p + 1, m, r, num.mulT(q[2 * p]).modxk(r - m));
			}
		};
		work(1, 0, n, mulT(q[1].inv(n)));
		return ans;
	}
};

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int n;
	cin >> n;

	vector<int> f;
	for (int i = 0; i < n; i++) {
		int a;
		cin >> a;
		if (a >= int(f.size())) {
			f.resize(a + 1);
		}
		f[a] = 1;
	}

	int mx = f.size() - 1;

	auto g = f;
	reverse(g.begin(), g.end());  //位置取反  //差的卷积
	auto h = Poly(f) * Poly(g);   //h 数组从mx开始为差值为0,后边以此类推


	return 0;
}

FWT

OR

void fwt_or(vector<ll> &a, int len) {
    for (int mid = 2; mid <= len; mid <<= 1) {
        for (int i = 0; i < len; i += mid) {
            for (int j = i; j < i + (mid >> 1); j++) {
                a[j + (mid >> 1)] += a[j];
			}
		}
	}
	return ;
}
void ifwt_or(vector<ll> &a, int len) {
    for (int mid = 2; mid <= len; mid <<= 1) {
        for (int i = 0; i < len; i += mid) {
            for (int j = i; j < i + (mid >> 1); j++) {
                a[j + (mid >> 1)] -= a[j];
			}
		}
	}
	return ;
}

AND

void fwt_and(vector<ll> &a, int len) {
    for (int mid = 2; mid <= len; mid <<= 1) {
        for (int i = 0; i < len; i += mid) {
            for (int j = i; j < i + (mid >> 1); j++) {
                a[j] += a[j + (mid >> 1)];
			}
		}
	}
	return ;
}
void ifwt_and(vector<ll> &a, int len) {
    for (int mid = 2; mid <= len; mid <<= 1) {
        for (int i = 0; i < len; i += mid) {
            for (int j = i; j < i + (mid >> 1); j++) {
                a[j] -= a[j + (mid >> 1)];
			}
		}
	}
	return ;
}

XOR

void fwt_xor(vector<ll> &a, int len) {
    for (int mid = 2; mid <= len; mid <<= 1) {
        for (int i = 0; i < len; i += mid) {
            for (int j = i; j < i + (mid >> 1); j++) {
                ll x = a[j], y = a[j + (mid >> 1)];
                a[j] = x + y, a[j + (mid >> 1)] = x - y;
            }
		}
	}
	return ;
}
void ifwt_xor(vector<ll> &a, int len) {
    for (int mid = 2; mid <= len; mid <<= 1) {
        for (int i = 0; i < len; i += mid) {
            for (int j = i; j < i + (mid >> 1); j++) {
                ll x = a[j], y = a[j + (mid >> 1)];
                a[j] = (x + y) >> 1, a[j + (mid >> 1)] = (x - y) >> 1;
            }
		}
	}
	return ;
}
上一篇:Linux中LVM与磁盘配额(内含详细操作)(六)


下一篇:[折腾日常]linux mint思维导图安装