数论

这个好久以前写的了,最近也没忙着专业课考试也没来得及弄这些,如果哪里有错请多包涵…
数论的东西主要还是靠理解,其实模板只是一个基础,真正遇到题肯定是需要变形的,这就需要对其有一个非常深刻的理解和认识了.所以主要还是理解原理
1.埃氏筛法
需要注意的是有些题没有必要打表 挨个判断即可 打表反而会超时

const int MAX_N=100000000;
bool vis[MAX_N+10];//vis数组表示该数是否为素数
void init(int n){//可不传值
    //int m=sqrt(n+0.5);
    int m=sqrt(MAX_N+0.5);//m的开方进一步缩小了计算范围
    /*
        原因我是这么理解的
            一个数如果不是素数,那么对于这个打表来说
            像26这种数字 它虽然是13的两倍,但是这个数早在i等于2的时候就已经被排除掉了
            故最极端的情况就是169这种数,他是一个数的平方
            唯一能判断出它不是素数的因子就是13即sqrt(n)
            然后为了能够正好判断出这种情况+0.5将这种情况包含进去
        至于证明的话网上我没找到..有的话或者我这个想法有问题麻烦告一下我 谢谢亲
    */
    for(int i=2;i<m;i++){
        if(!vis[i])//先判断当前数是否为素数
            for(int j=i*2;j<=MAX_N;j=j+i)
                vis[j]=true;//所有是i倍数的数肯定不是素数
    }
}

因为内存的问题 差不多1000万多就是打表的上限了
如果遇到更大的数就需要用到MR大数检测了

//速度更快的线性筛法
int prime[100001],mark[1000001];
int tot,phi[100001];
void getphi(int N){  
    phi[1]=1;//φ(1)=1  
    for(int i=2;i<=N;i++){
        if(!mark[i]){
            prime[++tot]=i;
            phi[i]=i-1;
        }  
        for(int j=1;j<=tot;j++){
            if(i*prime[j]>N) break;
            mark[i*prime[j]]=1;
            if(i%prime[j]==0){
                phi[i*prime[j]]=phi[i]*prime[j];break;  
            }  
            else phi[i*prime[j]]=phi[i]*phi[prime[j]];
        }  
    }  
}  

MR大数检测之前了解的时候是队友安利的,当时直接用的模板
既然是别人的东西就不粘了233,自行百度吧

2.辗转相除gcd
多写几遍就背出来了……

int gcd(int x,int y){
    return y ? gcd(y,x%y):x;
}

3.欧拉函数
和1一样 分清楚什么时候打表什么时候直接求解

//直接求解欧拉函数
int euler(int n){ //返回euler(n)
     int res=n,a=n;
     int temp=sqrt(a);//之前的模板这里存在重复计算
     for(int i=2;i<=temp;i++){
         if(a%i==0){
             res=res/i*(i-1);//防止数据溢出
             while(a%i==0) a/=i;
         }
     }
     if(a>1) res=res/a*(a-1);
     return res;
}
//筛选法打欧拉函数表
#define Max 1000001
int euler[Max];
void Init(){ 
     euler[1]=1;
     for(int i=2;i<Max;i++)
       euler[i]=i;
     for(int i=2;i<Max;i++)
        if(euler[i]==i)
           for(int j=i;j<Max;j+=i)
              euler[j]=euler[j]/i*(i-1);//防止数据溢出
}

4.快速幂
注意时刻取余,老丢…
极限点可以写ull 不过应该没题卡这个吧..

//如果需要实用快速幂说明n的大小偏大,所以非常有可能会溢出,故时刻取模是非常有必要的
typedef long long ll;
ll quick_pow(ll a,ll n,ll mod){
    if(n==0)
        return 1%mod;//如输入1 0 1的话 这里不取模会死==
    ll x=quick_pow(a,n/2,mod);//虽然是递归不过因为是指数增长,深度并不是很深
    ll ans=x*x%mod;
    if(n%2==1)
        ans=ans*a%mod;
    return ans;
}

ll quick_pow(ll a,ll n,ll mod){//递归总的来说没有循环快
    ll ans=1;
    while(n>0){
        if(n&1){
            ans*=a;
            ans%=mod;
        }
        a*=a;
        a%=mod;
        n>>=1;
    }
    return ans%mod;
}

5.扩展欧几里得
一定存在ax+by=gcd(a,b),事实上开个longlong保险些,被坑惨了..
这个我当时是看的这篇博客理解的:戳我
证明过程都在里面,这个就不说了

int a,b,x,y;//这里用了全局变量,所以调用就减少了x和y
void exgcd(int a,int b){  
    if(!b){  
        x=1;
        y=0;
        return;
    }
    exgcd(b,a%b);  
    int kkz=x;
    x=y;
    y=kkz-a/b*y;
    return;//之前这里少写了一个return;
}  

内容来说还是太少了,以后应该不断再添加吧,不过就是暑假集训的事情了,溜了溜了

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值