数论备忘录

1:数的表示

任何一个数都可以表示成下面的形式
N=p1^a1 * p2^a2 * p2^a2 * p2a2…pnan
1.pn表示质因子
2.an表示质因子的次幂

2:质数

a.质数的判断

//如果x|i,那么x|(x/i),如6/2=3,6/3=2,所以判断的时候只需要判断小的数就可以。
bool is_prime(int x)
{
    if(x==1) return false;
    if(x==2) return true;
    for(int i=2;i<=x/i;i++)
    {
        if(x%i==0) return false;
    }
    return true;
}

b.分解质因子

//需要注意x有且只有一个大于sqrt(n)的因子
//可以用k++的数组保存质数,或者用unordered_map保存质数和个数
void div_prime(int x)
{
    for(int i=2;i<=x/i;i++)
    {
        if(x%i==0)
        {
            int res=0;
            while(x%i==0)
            {
                res++;
                x/=i;
            }
            cout<<i<<' '<<res<<endl;
        }
    }
    if(x!=1) cout<<x<<' '<<1<<endl;
}

c.筛质数

//方案一:埃氏筛法
void pri(int x)
{
   for(int i=2;i<=x;i++)
   {
       if(book[i]%2==0)
       {
           p[idx++]=i;
           for(int j=2*i;j<=x;j+=i)
           {
               book[j]=1;
           }
       }
   }
}
//方案二:线性筛法
//可以顺便求出1-n的欧拉函数
void pri(int x)
{
    for(int i=2;i<=x;i++)
    {
        if(book[i]==0) p[idx++]=i;
        for(int j=0;p[j]<=x/i;j++)
        {
            book[p[j]*i]=1;
            if(i%p[j]==0) break;
        }
    }
}

3:约数

a.试处法求约数

/*
约数满足 x|i x|(x/i) 所以只需要判断小于sqrt(x)的数就可以,
存储,数组,vector,优先队列都可以
*/
void div(int x)
{
    a.clear();
    for (int i = 1; i <= x / i; i++)
    {
        if (x % i == 0)
        {
            a.push_back(i);
            if (i * i != x) a.push_back(x / i);
        }
    }
    sort(a.begin(),a.end());
    for(int i=0;i<a.size();i++) cout<<a[i]<<' ';
    cout<<endl;
}

b.求约数的个数

//首先有定理 约数个数 N=(a1+1)*a(2+1)*...*(an+1)
//分解质因子然后计算 不开longlong见祖宗
#include<iostream>
#include <unordered_map>

using namespace std;

int const N = 1e9+7;
unordered_map<int,int> map;

int main()
{
    int t; cin>>t;
    while(t--)
    {
        int n; cin>>n;
        for(int i=2;i<=n/i;i++)
        {
            if(n%i==0)
            {
                int res=0;
                while(n%i==0)
                {
                    res++;
                    n/=i;
                }
                map[i]+=res;
            }
        }
        if(n!=1) map[n]++;
    }
    long long sum=1;
    for(auto x:map)
    {
        sum=sum*(x.second+1)%N;
    }
    cout<<sum<<endl;
}

c.求约数的和

//约数和的定理
//( t=(t*p+1))
#include<iostream>
#include<queue>
#include<unordered_map>

using namespace std;

int const INF = 1e9+7;
unordered_map<int,int> map;

void pri(int x)
{
    for(int i=2;i<=x/i;i++)
    {
        if(x%i==0)
        {
            int res = 0;
            while(x%i==0)
            {
                res++;
                x/=i;
            }
            map[i]+=res;
        }
    }
    if(x!=1) map[x]++;
}

int main()
{
    int n; cin>>n;
    for(int i=1;i<=n;i++)
    {
        int x; cin>>x;
        pri(x);
    }
    long long res = 1;
    for(auto x:map)
    {
        int p = x.first;
        int a = x.second;
        long long sum = 1;
        while(a--)
        {
            sum=(sum*p+1)%INF;
        }
        res=res*sum%INF;
    }
    cout<<res<<endl;
}

d.最大公约数,最小公倍数

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

int lcm(int a,int b)
{
    return a/gcd(a,b)*b;
}

4:欧拉函数

//欧拉函数定义1-n互质的个数
//phi(x) = x * (1-p1) * (1-p2) * (1-p3) * ...... * (1-pk)

求n的欧拉函数

//分解n的质因子然后遍历
#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_map>

using namespace std;

unordered_map<int, int> map;

void pri(int x)
{
    for (int i = 2; i <= x / i; i++)
    {
        if (x % i == 0)
        {
            int res = 0;
            while (x % i == 0)
            {
                res++;
                x /= i;
            }
            map[i] += res;
        }
    }
    if (x != 1) map[x]++;
}

int main()
{
    int t; cin >> t;
    while (t--)
    {
        map.clear();
        int x; cin >> x;
        pri(x);
        long long sum = x;
        for(auto x:map)
        {
            sum=sum/x.first*(x.first-1);
        }
        cout<<sum<<endl;
    }
}

线性筛求欧拉函数

//可以求出1-n所有欧拉函数时间复杂度o(N)
#include<iostream>

using namespace std;

int const N = 1e6+10;
int p[N],idx;
int book[N];
int ol[N];

void pri(int n)
{
    ol[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(book[i]==0)
        {
            p[idx++] = i;
            ol[i]=i-1;
        }
        for(int j=0;p[j]<=n/i;j++)
        {
            book[p[j]*i]=1;
            if(i%p[j]==0)
            {
                ol[p[j]*i]=ol[i]*p[j];
                break;
            }
            else
            {
                ol[p[j]*i]=ol[i]*(p[j]-1);
            }
        }
    }
}
int main()
{
    int n; cin>>n;
    pri(n);
    long long sum=0;
    for(int i=1;i<=n;i++) sum+=ol[i]; 
    cout<<sum<<endl;
}

5.快速幂

LL res = 1;
    while(k)
    {
        if(k&1) res=res*a%p;
        a=a*a%p;
        k>>=1;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

道古九封

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值