数论基本问题模板

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

/*
 *  1. 欧几里得算法
 *  2. 扩展欧几里得算法
 *  3. 质因数分解,求约数个数
 *  4. 最low 筛素数,普通筛素数,线性筛素数
 *  5. 欧拉函数
 *  6. 快速幂
 */

/*  欧几里得算法
 *  给定两个整数a,b,求他们的最大公约数(a,b)
 */

int gcd(int a,int b)
{
    return b ? gcd(b,a % b) : a;
}

/*
 *  裴属定理:
 *  给定任意正整数 a,b d = gcd(a,b); ax + by = d,
 *  a,b能组成的最小的正整数就是d
 *
 *  扩展欧几里得 就可以求出系数
 */

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

/*
 *  质因数分解:
 *  算术基本定理 n 一定可以分解为这个样子,p是质数
 *      n = p1^a1 + p2^a2 + ...pm^am;
 *  1.可以n 一共有多少个约数 (a1 + 1) * (a2 + 1) * .. *(am + 1);
 *  2.可以求出欧拉数(小于n且与互质的数的个数)
 *  phi(n) = n * (1 - 1 / p1) * (1 - 1 / p2) * .... * (1 - 1 / pm)
 *  证明:
 *  (1) n 是个质数,n = p , phi(n) = phi(p) = p - 1;
 *  (2) n = p ^ k, phi(n) = n - n / p = n * (1 - 1 / p);
 *      1 - n 里面与n 不互质的数为 p 的倍数,p 的倍数的个数为 n / p;
 *      p,2p,3p,4p,5p, ... n/p*p;一共有 n / p 个数
 *  (3) n = p1^a1 + p2^a2 + ...pm^am
 *          p1 的倍数为 n / p1个
 *          p2 的倍数为 n / p2个
 *   证明比较复杂就自己去网上搜吧;
 */
const int N = 100010;
bool st[N];
int primes[N];

/*
 * 筛素数 1. 暴力筛素数 n * sqrt(n)
 *        2.筛法筛素数 复杂度为O(n * ln(n));
 *        3. 线性素数筛法,O(n)
 *
*/

/*
 *  小于n且与n互质的数的和为 euler(n) * n / 2
 *      gcd(a,n) = 1 ,gcd(n,n - a) = 1
 */


int f2(int n)
{
    int cnt = 0;
    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;
    }
    for(int i = 0;i < cnt;i ++)cout << primes[i] << " ";
    cout << endl;
    // n / 2 + n / 3 + n / 4 + ...
    // n * (1 / 2 + 1 / 3 + 1 / 4 .... + 1 / n) 约等于 ln(n) + C(常数)
    return 0;
}

void f3(int n)
{
    // 保证每个数只会被他自己的最小质数筛掉
    int cnt = 0;
    for(int i = 2;i <= n;i ++)
    {
        if(!st[i])
        {
            primes[cnt++] = i;
        }

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

    return 0;
}


int main()
{


    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值