基础数论模板与公式

1.素数判定
1.1试除法判素数

bool is_prime(int x)
{
    if (x < 2) return false;
    for (int i = 2; i <= x / i; i ++ )
        if (x % i == 0)
            return false;
    return true;
}

1.2 Miller−Rabin 判定法

ll Rand() {//决定了程序的性能
    static ll x = (srand((int)time(0)), rand());
    x += 1000003;
    if (x > 1000000007)
        x -= 1000000007;
    
    return x;
}
bool Witness(ll a, ll n) {
    ll t = 0, u = n - 1;
    while (!(u & 1))
        u >>= 1, t++;
    ll x = qpow(a, u, n), y;//qpow为快速幂

    while (t--) {
        y = x * x % n;
        if (y == 1 && x != 1 && x != n - 1)
            return true;
        x = y;
    }
    return x != 1;
}
bool MillerRabin(ll n, ll s) {
    if (n == 2 || n == 3 || n == 5)
        return 1;

    if (n % 2 == 0 || n % 3 == 0 || n % 5 == 0 || n == 1)
        return 0;

    while (s--) {
        if (Witness(Rand() % (n - 1) + 1, n))
            return false;
    }
    return true;
}

1.3埃氏筛

int primes[N], cnt;     // primes[]存储所有素数
bool st[N];         // st[x]存储x是否被筛掉

void get_primes(int n)
{
    for (int i = 2; i <= n; i ++ )
    {
        if (st[i]) continue;
        primes[cnt ++ ] = i;
        for (int j = i + i; j <= n; j += i)
            st[j] = true;
    }
}

1.4线性筛

int primes[N], cnt;     // primes[]存储所有素数
bool st[N];         // st[x]存储x是否被筛掉

void get_primes(int n)
{
    for (int i = 2; i <= n; i ++ )
    {
        if (!st[i]) primes[cnt ++ ] = i;
        for (int j = 0; primes[j] <= n / i; j ++ )
        {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0) break;
        }
    }
}

2.质因数分解
2.1试除法分解

void divide(int x)
{
    for (int i = 2; i <= x / i; i ++ )
        if (x % i == 0)
        {
            int s = 0;
            while (x % i == 0) x /= i, s ++ ;
            cout << i << ' ' << s << endl;
        }
    if (x > 1) cout << x << ' ' << 1 << endl;
    cout << endl;
}

2.2 Pollard Rho 算法
见到的几种实现:
1-----------------------

#include<bits/stdc++.h>
#define ll long long
#define fi first
#define se second
using namespace std;
const int N = 1e5 + 7;
ll x, y, a[N];
ll max_factor;
struct BigIntegerFactor {
    const static int N = 1e6 + 7;
    const static ll inf=0x3f3f3f3f3f3f3f3f;
    ll prime[N], p[N], fac[N], sz, cnt; //多组输入注意初始化cnt = 0
    inline ll mul(ll a, ll b, ll mod) {          //WA了尝试改为__int128或慢速乘
        if (mod <= 1000000000)
            return a * b % mod;
        return (a * b - (ll)((long double)a / mod * b + 1e-8) * mod + mod) % mod;
    }
    void init(int maxn) //线性筛 
	{
        int tot = 0;
        sz = maxn - 1;
        for (int i = 1; i <= sz; ++i)
            p[i] = i;
        for (int i = 2; i <= sz; ++i) {
            if (p[i] == i)
                prime[tot++] = i;
            for (int j = 0; j < tot && 1ll * i * prime[j] <= sz; ++j) {
                p[i * prime[j]] = prime[j];
                if (i % prime[j] == 0)
                    break;
            }
        }
    }
    ll qpow(ll a, ll x, ll mod)
	{
        ll res = 1ll;
        while (x) {
            if (x & 1)
                res = mul(res, a, mod);
            a = mul(a, a, mod);
            x >>= 1;
        }
        return res;
    }
    bool check(ll a, ll n) {                     //二次探测原理检验n
        ll t = 0, u = n - 1;
        while (!(u & 1))
            t++, u >>= 1;
        ll x = qpow(a, u, n), xx = 0;
        while (t--) {
            xx = mul(x, x, n);
            if (xx == 1 && x != 1 && x != n - 1)
                return false;
            x = xx;
        }
        return xx == 1;
    }
    bool miller(ll n, int k) {
        if (n == 2)
            return true;
        if (n < 2 || !(n & 1))
            return false;
        if (n <= sz)
            return p[n] == n;
        for (int i = 0; i <= k; ++i) {            //测试k次
            if (!check(rand() % (n - 1) + 1, n))
                return false;
        }
        return true;
    }
    inline ll gcd(ll a, ll b) {
        return b == 0 ? a : gcd(b, a % b);
    }
    inline ll Abs(ll x) {
        return x < 0 ? -x : x;
    }
    ll Pollard_rho(ll n) {                 //基于路径倍增的Pollard_Rho算法
        ll s = 0, t = 0, c = rand() % (n - 1) + 1, v = 1, ed = 1;
        while (1) {
            for (int i = 1; i <= ed; ++i) {
                t = (mul(t, t, n) + c) % n;
                v = mul(v, Abs(t - s), n);
                if (i % 127 == 0) {
                    ll d = gcd(v, n);
                    if (d > 1)
                        return d;
                }
            }
            ll d = gcd(v, n);

            if (d > 1)
                return d;
            s = t;
            v = 1;
            ed <<= 1;
        }
    }
    void getfactor(ll n) {                         //得到所有的质因子(可能有重复的)
        if (n <= sz) {
            while (n != 1)
                fac[cnt ++ ] = p[n], n /= p[n];
            max_factor = max_factor > p[n] ? max_factor : p[n];
            return;
        }
        if (miller(n, 6)) {
            fac[cnt ++ ] = n;
            max_factor = max_factor > n ? max_factor : n;
        }
        else {
            ll d = n;
            while (d >= n)
                d = Pollard_rho(n);
            getfactor(d);
            getfactor(n / d);
        }
        return ;
    }
    ll cal(ll n,ll p){
		ll ans=0;
		while(n)
		{
		    ans+=n/p;
		    n/=p;
		}
		return ans;
	}
	ll slove(ll n,ll x,ll y){
		cnt=0;
		map<ll,ll> mm;
		getfactor(x);
		ll ans=inf;
		for(int i;i<cnt;i++)
		{
			mm[fac[i]]++;
		}
		for(auto it:mm)
		{
			ll num=0;
			for(int i=0;i<n;i++)
			{
				num+=cal(a[i],it.fi);
			}
			ans=min(ans,(cal(y,it.fi)-num)/it.se);
		}
		return ans;
	}
}Q;

int main()
{
	//Q.init(N - 1);//如果代码超时且仅需要分解大数的质因数可以用这句话,否则不要用
    ll t;
    scanf("%lld",&t);
    while(t--)
    {
    	
	}
}

2-----------------------------------------

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 1e5 + 7;
const ll mod = 998244353;

unordered_map <ll, ll> mp;
  
namespace rho{
    const int MAXP = 1000010;
    const int BASE[] = {2, 450775, 1795265022, 9780504, 28178, 9375, 325};

    long long seq[MAXP];
    int primes[MAXP], spf[MAXP];


    long long gcd(long long a, long long b) {
        int ret = 0;
        while(a) {
            for( ; !(a & 1) && !(b & 1); ++ret, a >>= 1, b >>= 1);
            for( ; !(a & 1); a >>= 1);
            for( ; !(b & 1); b >>= 1);
            if(a < b) swap(a, b);
            a -= b;
        }
        return b << ret;
    }

    inline long long mod_add(long long x, long long y, long long m){
        return (x += y) < m ? x : x - m;
    }

    inline long long mod_mul(long long x, long long y, long long m){
        long long res = x * y - (long long)((long double)x * y / m + 0.5) * m;
        return res < 0 ? res + m : res;
    }

    inline long long mod_pow(long long x, long long n, long long m){
        long long res = 1 % m;
        for (; n; n >>= 1){
            if (n & 1) res = mod_mul(res, x, m);
            x = mod_mul(x, x, m);
        }

        return res;
    }

    inline bool miller_rabin(long long n){
        if (n <= 2 || (n & 1 ^ 1)) return (n == 2);
        if (n < MAXP) return spf[n] == n;

        long long c, d, s = 0, r = n - 1;
        for (; !(r & 1); r >>= 1, s++) {}

        for (int i = 0; primes[i] < n && primes[i] < 32; i++){
            c = mod_pow(primes[i], r, n);
            for (int j = 0; j < s; j++){
                d = mod_mul(c, c, n);
                if (d == 1 && c != 1 && c != (n - 1)) return false;
                c = d;
            }

            if (c != 1) return false;
        }
        return true;
    }

    inline void init(){
        int i, j, k, cnt = 0;

        for (i = 2; i < MAXP; i++){
            if (!spf[i]) primes[cnt++] = spf[i] = i;
            for (j = 0, k; (k = i * primes[j]) < MAXP; j++){
                spf[k] = primes[j];
                if(spf[i] == spf[k]) break;
            }
        }
    }

    long long pollard_rho(long long n){
        while (1){
            long long x = rand() % n, y = x, c = rand() % n, u = 1, v, t = 0;
            long long *px = seq, *py = seq;

            while (1){
                *py++ = y = mod_add(mod_mul(y, y, n), c, n);
                *py++ = y = mod_add(mod_mul(y, y, n), c, n);
                if((x = *px++) == y) break;

                v = u;
                u = mod_mul(u, abs(y - x), n);

                if (!u) return gcd(v, n);
                if (++t == 32){
                    t = 0;
                    if ((u = gcd(u, n)) > 1 && u < n) return u;
                }
            }

            if (t && (u = gcd(u, n)) > 1 && u < n) return u;
        }
    }

    vector <long long> factorize(long long n){
        if (n == 1) return vector <long long>();
        if (miller_rabin(n)) return vector<long long> {n};

        vector <long long> v, w;
        while (n > 1 && n < MAXP){
            v.push_back(spf[n]);
            n /= spf[n];
        }

        if (n >= MAXP) {
            long long x = pollard_rho(n);
            v = factorize(x);
            w = factorize(n / x);
            v.insert(v.end(), w.begin(), w.end());
        }

        sort(v.begin(), v.end());
        return v;
    }
} 

signed main() {
    // Q.init(N - 1);//如果代码超时且仅需要分解大数的质因数可以用这句话,否则不要用
    ll T, n;
    rho :: init();
    scanf("%lld", &T);
    while (T--) { 
        scanf("%lld", &n);
        vector <ll> res = rho :: factorize(n); 
        for(auto it : res)
        	mp[it] ++ ;
    }
    ll ans = 1;
    for(auto it : mp)
    	ans = (ans * (it.second + 1)) % mod;
    printf("%lld\n", ans);
    return 0;
}

3----这个是最快的(T了可以试试,比2快了有一倍)

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxp = 1e6 + 1, maxv = 25, maxc = (int)1e4 + 1;
int ptot, pr[maxp], d[maxp], cnt;
LL n, p[maxc];
LL mod_add(LL x, LL y, LL p) {
	return (x += y) < p ? x : x - p;
}
LL mod_mul(LL x, LL y, LL p) {
	LL ret = x * y - (LL)((long double)x * y / p + 0.5) * p;
	return ret < 0 ? ret + p : ret;
}
LL mod_pow(LL x, LL k, LL p) {
	LL ret = 1 % p;
	for( ; k > 0; k >>= 1, x = mod_mul(x, x, p))
		(k & 1) && (ret = mod_mul(ret, x, p));
	return ret;
}
bool miller_rabin(LL n) {
	if(n == 2) return 1;
	if(n < 2 || !(n & 1))
		return 0;
	LL s = 0, r = n - 1;
	for( ; !(r & 1); r >>= 1, ++s);
	for(int i = 0; pr[i] < n && pr[i] < maxv; ++i) {
		LL cur = mod_pow(pr[i], r, n), nxt;
		for(int j = 0; j < s; ++j) {
			nxt = mod_mul(cur, cur, n);
			if(nxt == 1 && cur != 1 && cur != n - 1) return 0;
			cur = nxt;
		}
		if(cur != 1) return 0;
	}
	return 1;
}
LL gcd(LL a, LL b) {
	int ret = 0;
	while(a) {
		for( ; !(a & 1) && !(b & 1); ++ret, a >>= 1, b >>= 1);
		for( ; !(a & 1); a >>= 1);
		for( ; !(b & 1); b >>= 1);
		if(a < b)
			swap(a, b);
		a -= b;
	}
	return b << ret;
}
LL pollard_rho(LL n) {
	static LL seq[maxp];
	while(1) {
		LL x = rand() % n, y = x, c = rand() % n;
		LL *px = seq, *py = seq, tim = 0, prd = 1;
		while(1) {
			*py++ = y = mod_add(mod_mul(y, y, n), c, n);
			*py++ = y = mod_add(mod_mul(y, y, n), c, n);
			if((x = *px++) == y) break;
			LL tmp = prd;
			prd = mod_mul(prd, abs(y - x), n);
			if(!prd) return gcd(tmp, n);
			if((++tim) == maxv) {
				if((prd = gcd(prd, n)) > 1 && prd < n) return prd;
				tim = 0;
			}
		}
		if(tim && (prd = gcd(prd, n)) > 1 && prd < n) return prd;
	}
}
void decompose(LL n) {
	for(int i = 0; i < cnt; ++i)
		if(n % p[i] == 0) {
			p[cnt++] = p[i];
			n /= p[i];
		}
	if(n < maxp) {
		for( ; n > 1; p[cnt++] = d[n], n /= d[n]);
	} else if(miller_rabin(n)) {
		p[cnt++] = n;
	} else {
		LL fact = pollard_rho(n);
		decompose(fact), decompose(n / fact);
	}
} // prepare pr(prime) and d(minimal factor)
int main() {
	for(int i = 2; i < maxp; ++i) {
		if(!d[i])
			pr[ptot++] = d[i] = i;
		for(int j = 0, k; (k = i * pr[j]) < maxp; ++j) {
			d[k] = pr[j];
			if(d[i] == pr[j])
				break;
		}
	}
	int m, mod = 998244353;
	scanf("%d", &m);
	while(m--) {
		scanf("%lld", &n);
		decompose(n);
	}
	sort(p, p + cnt);
	int ans = 1;
	for(int i = 0; i < cnt; ) {
		int ctr = 0;
		for(LL pp = p[i]; i < cnt && p[i] == pp; ++i, ++ctr);
		ans = ans * (ctr + 1LL) % mod;
	}
	printf("%d\n", ans);
	return 0;
}

3.因数
3.1 试除法找因数

vector<int> get_divisors(int x)
{
    vector<int> res;
    for (int i = 1; i <= x / i; i ++ )
        if (x % i == 0)
        {
            res.push_back(i);
            if (i != x / i) res.push_back(x / i);
        }
    sort(res.begin(), res.end());
    return res;
}

3.2枚举倍数找因数(常用于一些于因子有关的计算,通过枚举倍数nlogn求解)

    for(int i = 1; i <= n; ++ i){
        for(int j = 1 ;j * i <= n; ++ j){
            factor[i * j].push_back(j);
        }
    }
    for(int i = 1; i <= n; ++ i){
        cout << i << ": ";
        for(int j = 0; j < factor[i].size(); ++ j)
            printf("%d ", factor[i][j]);
        puts("");
    }

3.3 一些性质

如果 N = p1^c1 * p2^c2 * … *pk^ck
约数个数: (c1 + 1) * (c2 + 1) * … * (ck + 1)
约数之和: (p1^0 + p1^1 + … + p1^c1) * … * (pk^0 + pk^1 + …+ pk^ck)

3.4 最大公约数,最小公倍数
4.欧拉函数
4.1按定义求

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

    return res;
}

4.2 筛法求欧拉函数

int primes[N], cnt;     // primes[]存储所有素数
int euler[N];           // 存储每个数的欧拉函数
bool st[N];         // st[x]存储x是否被筛掉


void get_eulers(int n)
{
    euler[1] = 1;
    for (int i = 2; i <= n; i ++ )
    {
        if (!st[i])
        {
            primes[cnt ++ ] = i;
            euler[i] = i - 1;
        }
        for (int j = 0; primes[j] <= n / i; j ++ )
        {
            int t = primes[j] * i;
            st[t] = true;
            if (i % primes[j] == 0)
            {
                euler[t] = euler[i] * primes[j];
                break;
            }
            euler[t] = euler[i] * (primes[j] - 1);
        }
    }
}

5.同余
5.1快速幂

int qmi(int m, int k, int p)
{
    int res = 1 % p, t = m;
    while (k)
    {
        if (k&1) res = res * t % p;
        t = t * t % p;
        k >>= 1;
    }
    return res;
}

5.2龟速乘

ll Mul(ll a, ll b, ll p)
{ 
	if(b < 0) a = - a, b = - b;
	ll res = 0;//因为是加法模拟乘法,所以res开始为0
	while(b) {
		if(b & 1) res = (res + a) % p;
		a = (a + a) % p;
		b >>= 1;
	}
	return res;
}

5.3 欧拉定理
5.4 费马小定理
5.5 威尔逊定理
6.拓展欧几里得
6.1 拓展欧几里得算法

// 求x, y,使得ax + by = gcd(a, b)
int exgcd(int a, int b, int &x, int &y)
{
    if (!b)
    {
        x = 1; y = 0;
        return a;
    }
    int d = exgcd(b, a % b, y, x);
    y -= (a/b) * x;
    return d;
}
  1. 逆元
    7.1费马小定理求逆元
int inv(int x,int p) {return qpow(x, mod - 2, p) % p;}

7.2拓展欧几里得求逆元

int inv(int a,int mod)
{
	int x,y;
	exgcd(a,mod,x,y);
    return (x % mod + mod) % mod;
}

7.3线性递推求逆元

inv[1] = 1;
for (int i = 2; i <= n; ++i) {
	inv[i] = (long long)(p - p / i) * inv[p % i] % p;
}

7.4求阶乘逆元
8.线性同余
9.高次同余方程
9.1 bsgs与exbsgs算法模板

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+7;
const int mod=998244353;
const ll INF=0x3f3f3f3f3f3f3f3f;
ll hs[N], head[N], nexts[N], id[N], top;
void insert(ll x, ll y, ll mod) //mod传 N
{
	ll k = x % mod;
	hs[top] = x;
	id[top] = y;
	nexts[top] = head[k];
	head[k] = top++;
}
ll find(ll x, ll mod)
{
	ll k = x % mod;
	for (int i = head[k]; i != -1; i = nexts[i])
		if (hs[i] == x)
			return id[i];
	return -1;
}
ll gcd(ll a, ll b)
{
	return b == 0 ? a : gcd(b, a % b);
}
ll BSGS(ll a, ll b, ll p, ll a1) //质数传1
{
	memset(head, -1, sizeof(head));
	top = 1;
	a %= p, b %= p;
	if (a1 == 1 && 1 % p == b % p)
		return 0;
	if (a == 0)
	{
		if (b == 0)
			return 1;
		else
			return -1;
	}
	//unordered_map<ll, ll> hash; //map  unordered_map 都试试
	ll k = sqrt(p) + 1;
	ll ak = 1;
	for (ll i = 0; i < k; ++i)
	{
		ll t = ak * b % p;
		insert(t, i, N);
		//hash[t] = i;
		ak = ak * a % p;
	}
	for (ll i = 0; i <= k; ++i)
	{
		/* if (hash.count(a1) && i * k - hash[a1] >= 0)
			return i * k - hash[a1]; */
		ll j = find(a1, N);
		if (j != -1 && i * k - j >= 0)
			return i * k - j;
		a1 = a1 * ak % p;
	}
	return -1;
}
ll exBSGS(ll a, ll b, ll p)
{
	a %= p, b %= p;
	if (b == 1 || p == 1)
		return 0;
	ll cnt = 0, a1 = 1;
	ll d = gcd(a, p);
	while (d > 1)
	{
		if (b % d)
			return -1;
		p /= d;
		b /= d;
		a1 = (a1 * a / d) % p;
		++cnt;
		if (b == a1)
			return cnt;
		d = gcd(a, p);
	}
	ll res = BSGS(a, b, p, a1);
	if (res == -1)
		return -1;
	else
		return res + cnt;
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值