数论算法的一些模板

数论

质数

哥德巴赫猜想

哥德巴赫猜想的内容如下:

任意一个大于 4 的偶数都可以拆成两个奇素数之和。

例如:

8=3+5
20=3+17=7+13
42=5+37=11+31=13+29=19+23
现在,你的任务是验证所有小于一百万的偶数能否满足哥德巴赫猜想。

6≤n<106
#include <iostream>

using namespace std;

const int N = 1000010;

int prime[N], cnt;
bool st[N];

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

int main(void) {
    init(N - 1);

    int n;
    while (cin >> n, n) {
        
        for (int i = 1; ; ++i) {
            int x = prime[i], y = n - x;
            if (!st[y]) {
                printf("%d = %d + %d\n", n, x, y);
                break;
            }
        }
    }

    return 0;
}

质数距离

给定两个整数 L 和 U,你需要在闭区间 [L,U] 内找到距离最接近的两个相邻质数 C1 和 C2(即 C2−C1 是最小的),如果存在相同距离的其他相邻质数对,则输出第一对。

同时,你还需要找到距离最远的两个相邻质数 D1 和 D2(即 D1−D2 是最大的),如果存在相同距离的其他相邻质数对,则输出第一对。

1≤L<U≤2^31−1
#include <iostream>
#include <cstring>

using namespace std;

typedef long long LL;

const int N = 1000010;

int prime[N], cnt;
bool st[N];

int init(int n) {
    memset(st, false, sizeof st);
    for (int i = 2; i <= n; ++i) {
        if (!st[i]) prime[++cnt] = i;
        for (int j = 1; prime[j] <= n / i; ++j) {
            st[prime[j] * i] = true;
            if (i % prime[j] == 0) break;
        }
    }
}

signed main(void) {
    int l, r;
    while (cin >> l >> r) {
        init (50000);
        memset(st, false, sizeof st);

        for (int i = 1; i <= cnt; ++i) {
            LL p = prime[i];
            for (LL j = max(p * 2, (l + p - 1) / p * p); j <= r; j += p) {
                st[j - l] = true;
            }
        }

        cnt = 0;
        for (int i = 0; i <= r - l; ++i) {
            if (!st[i] && i + l >= 2)
                prime[++cnt] = i + l;
        }

        if (cnt < 2) {
            puts("There are no adjacent primes.");
            continue;
        }

        int a = 1, b = 1;
        for (int i = 1; i + 1 <= cnt; ++i) {
            int d = prime[i + 1] - prime[i];
            if (d < prime[a + 1] - prime[a]) a = i;
            if (d > prime[b + 1] - prime[b]) b = i;
        }

        printf("%d,%d are closest, %d,%d are most distant.\n", 
            prime[a], prime[a + 1], prime[b], prime[b + 1]);
    }
}

分解质因数

将n分解质因数,输出底数和指数

void solve() {
    int n;
    cin >> n;

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

阶乘分解

给定整数 N,试把阶乘 N! 分解质因数,按照算术基本定理的形式输出分解结果中的 pi 和 ci 即可。
#include <iostream>

using namespace std;

const int N = 1000010;

int prime[N], cnt;
bool st[N];
int n;

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

int main(void)
{
    int n;
    cin >> n;

    init(n);

    for (int i = 1; i <= cnt; ++i) {
        int p = prime[i];
        int s = 0;
        for (int j = n; j; j /= p) {
            s += j / p;
        }
        cout << p << ' ' << s <<endl;
    }

    return 0;
}

约数

约数个数

输入n个正整数,求他们成绩的约数个数

(s1+1)*(s2+1)*...*(sn+1)

#include <iostream>
#include <unordered_map>

using namespace std;

const int MOD = 1e9 + 7;

int main(void) {
    int n;
    cin >> n;

    unordered_map<int, int> mp;
    while (n--) {
        int x;
        cin >> x;

        for (int i = 2; i <= x / i; ++i) {
            if (x % i == 0) {
                int s = 0;
                while (x % i == 0) x /= i, s++;
                mp[i] += s;
            }
        }
        if (x > 1) mp[x] += 1;
    }

    //LL
    int res = 1;
    for (auto it : mp) {
        int s = it.second;
        res = (long long)res * (s + 1) % MOD;
    }

    cout << res;

    return 0;
}

约数之和

输入n个数,求它们乘积的约数之和

(p^0+p^1+...+p^k)*()...*()

#include <iostream>
#include <unordered_map>

using namespace std;

const int MOD = 1e9 + 7;

typedef long long LL;

int main(void) {
    int n;
    cin >> n;

    unordered_map<int, int> mp;
    while (n--) {
        int x;
        cin >> x;

        for (int i = 2; i <= x / i; ++i) {
            if (x % i == 0) {
                int s = 0;
                while (x % i == 0) x /= i, s++;
                mp[i] += s;
            }
        }
        if (x > 1) mp[x] += 1;
    }

    int res = 1;
    for (auto e : mp) {
        int p = e.first, s = e.second;

        int t = 1;
        while (s--) {
            t = ((LL)t * p + 1l) % MOD;
        }

        res = (LL) res * t % MOD;
    }

    cout << res;

    return 0;
}

反素数

对于任何正整数 x,其约数的个数记作 g(x),例如 g(1)=1、g(6)=4。

如果某个正整数 x 满足:对于任意的小于 x 的正整数 i,都有 g(x)>g(i),则称 x 为反素数。

例如,整数 1,2,4,6 等都是反素数。

现在给定一个数 N,请求出不超过 N 的最大的反素数。

1≤N≤2∗10^9
#include <iostream>

using namespace std;

int prime[9] = {2, 3, 5, 7, 11, 13, 17, 19, 23};
int maxv, number;
int n;

void dfs(int u, int last, int p, int s)
{
    if (s > maxv || s == maxv && p < number) {
        number = p;
        maxv = s;
    }

    if (u == 9) return;

    for (int i = 1; i <= last; ++i) {
        if ((long long) p * prime[u] > n) break;
        p *= prime[u];
        dfs(u + 1, i, p, s * (i + 1));
    }
}

int main(void)
{
    cin >> n;
    dfs(0, 30, 1, 1);

    cout << number;
    return 0;
}

欧拉函数

欧拉函数

1~n中与n互质的数的个数

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

    cout << res << endl;
}

欧拉筛

const int N = 1000010;
int prime[N], cnt, phi[N];
bool st[N];
void get_phi(int n) {
    phi[1] = 1;
    for (int i = 2; i <= n; ++i) {
        if (!st[i]) {
            prime[++cnt] = i;
            phi[i] = i - 1;
        }
        for (int j = 1; prime[j] <= n / i; ++j) {
            st[prime[j] * i] = true;
            if (i % prime[j] == 0) {
                phi[prime[j] * i] = prime[j] * phi[i];
                break;
            }
            phi[prime[j] * i] = phi[i] * (prime[j] - 1);
        }
    }
}

扩展欧几里得

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;
}

组合数

组合数

组合数

输出C(b,a)

C(b,a) -> C[a][b]

void init() {
    for (int i = 0; i < N; ++i)
        for (int j = 0; j <= i; ++j)
            if (!j) c[i][j] = 1;
            else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % MOD; 
}

组合数II

求C(b,a)%mod

给定a,b。输出C(b,a)

1<=b<=a<=1e5

#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 100010, mod = 1e9 + 7;


int fact[N], infact[N];


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


int main()
{
    fact[0] = infact[0] = 1;
    for (int i = 1; i < N; i ++ )
    {
        fact[i] = (LL)fact[i - 1] * i % mod;
        infact[i] = (LL)infact[i - 1] * qmi(i, mod - 2, mod) % mod;
    }


    int n;
    scanf("%d", &n);
    while (n -- )
    {
        int a, b;
        scanf("%d%d", &a, &b);
        printf("%d\n", (LL)fact[a] * infact[b] % mod * infact[a - b] % mod);
    }

    return 0;
}

组合数III

求C(b,a)%mod

给定a,b,p,其中p是质数。输出C(b,a)%p

1<=n<=20, 1<=b<=a<=1e18, 1<=p<=1e5

#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;


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


int C(int a, int b, int p)
{
    if (b > a) return 0;

    int res = 1;
    for (int i = 1, j = a; i <= b; i ++, j -- )
    {
        res = (LL)res * j % p;
        res = (LL)res * qmi(i, p - 2, p) % p;
    }
    return res;
}


int lucas(LL a, LL b, int p)
{
    if (a < p && b < p) return C(a, b, p);
    return (LL)C(a % p, b % p, p) * lucas(a / p, b / p, p) % p;
}


int main()
{
    int n;
    cin >> n;

    while (n -- )
    {
        LL a, b;
        int p;
        cin >> a >> b >> p;
        cout << lucas(a, b, p) << endl;
    }

    return 0;
}
posted @ 2021-07-10 14:22  yangruomao  阅读(171)  评论(0编辑  收藏  举报