数论

一个数约数个数=所有素因子的次数+1的乘积
举个例子就是48 = 2 ^ 4 * 3 ^ 1,所以它有(4 + 1) * (1 + 1) = 10个约数
****************************************************************************************************** 辗转相除 最大公约数 gcd(a,b): int gcd(int a,int b){ return b==0?a:gcd(b,a%b); } 如果b大于a则第一次递归转换a和b的值。 *************************************************************************************************** 最小公倍数 lcm(a,b): 利用gcd可以求出两个数a,b的最小公倍数数,有唯一分解定理得 a=p1^e1*p2^e2*...*pn^en; b=p1^f1*p2^f2*...*pn^fn; 则 gcd(a,b)=p1^min(e1,f1)*p2^min(e2,f2)*...*pn^min(en,fn); lcm(a,b)=p1^max(e1,f1)*p2^max(e2,f2)*...*pn^max(en,fn); 有gcd(a,b)*lcm(a,b)=a*b。如果把lcm写成a*b/gcd(a,b),可能会因此丢掉不少分数——a*b可能会溢出!正确的写法是先除后乘,即 a/gcd(a,b)*b。 ************************************************************************************************************* 素数帅选:对于不超过n的每一个非负整数p,删除2p,3p,4p,...,当处理完所有数之后,还没有被删除的就是素数,若用vis[i]表示i已被删除 memset(vis,0,sizeof(vis)); for(int i=2;i<=n;i++) for(int j=i*2;j<=n;j+=i) vis[j]=1; 改进: int m=sqrt(n+0.5); memset(vis,0,sizeof(vis)); for(int i=2;i<=m;i++)   if(!vis[i]) for(int j=i*i;j<=n;j+=i)   vis[j]=1; ******************************************************************************************************************* 扩展欧几里德算法: 找出一对整数(x,y),使得ax+by=gcd(a,b)。这里的x,y不一定是正数,也可能是负数或0。例如gcd(6,15)=3,6*3-15*1=3,其中x=3,y=-1。这个 方程还有其他解,如x=-2,y=1。 程序: void gcd(int a,int b,int &d,int &x,int &y){ if(!b){ d=a;x=1;y=0; }else{ gcd(b,a%b,d,y,x); y-=x*(a/b); } }  

  这个解的x就是a关于b的逆元

  y就是b关于a的逆元

更一般的推论:
设a,b,c为任意整数。若方程ax+by=c的一组整数解为(x0,y0),则它的任意整数解都可以写成(x0+kB,y0-kA),其中A=a/gcd(a,b),B=b/gcd(a,b),
(如果gcd(a,b)=0,意味着或b等于0,可以特殊判断)k取任意整数。
设a,b,c为任意整数,g=gcd(a,b),方程ax+by=g的一组解(x0,y0),则当c是g的倍数时ax+by=c的一组解是(x0c/g,y0c/g);当c不是g的整数倍时无整数解。
****************************************************************************************************************************
同余与模运算:
(a+b)mod n=((a mod n)+(b mod n))mod n
(a-b)mod n=((a mod n)-(b mod n)+n)mod n
ab mod n=(a mod n)(b mod n) mod n
减法中a mod n可能小于b mod n,需要在结果加上n。乘法中(a mod n)(b mod n)有时可能会溢出需要用long long,例如:
int mul_mod(int a,int b,int n){
    a%=n;b%=n;
    return (int)((long long)a*b%n);
}
大整数取模 输入n,m,输出n mod m。
把大整数写成"自左向右"的形式:1234=((1*10+2)*10+3)*10+4,用前面的公式每步求模:
scanf("%s%d",n,&m);
int len=strlen(n);
int ans=0;
for(int i=0;i<len;i++)
ans=(int)(((long long)ans*10+n[i]-'0')%m);
printf("%d
",ans);
幂取模 输入a,n,m,输出a^n mod m。
分治法对半递归计算:
int pow_mod(int a,int n,int m){
    if(n==0) return 1;
    int x=pow_mod(a,n/2,m);
    long long ans=(long long)x*x%m;
    if(n&1) ans=ans*a%m;
    return (int)ans;
}
线性方程组 输入a,b,n,解方程ax≡b(mod n)。
a≡b(mod n)表示a和b关于模n同余,即a mod n=b mod n。ax≡b(mod n)的充要条件是a-b是n的整数倍。
这样原方程就可以理解为ax-b是n的整数倍,设这个倍数为y,则ax-b=ny,移项ax-ny=b,这就是前面的扩展欧几里德。
当b=1时,ax≡1(mod n),此时方程的解称为a关于模n的逆。当gcd(a,n)=1时,该方程有唯一解;否则无解。
(a^b)%p=((a%p)^(e(p)+b%e(p)))%p  其中e(p)表示P的欧拉函数值
**************************************************************************************************************
除法取余:
(a/b)%mod,当a,b非常大时无法计算。
费马小定理(Fermat Theory)是数论中的一个重要定理,其内容为: 假如p是质数,且gcd(a,p)=1,那么 a^(p-1)≡1(mod p)。即:假如a是整数
p是质数,且a,p互质(即两者只有一个公约数1),那么a的(p-1)次方除以p的余数恒等于1。

  可以用乘法的逆来解决,当然可知当成定理来用(a/b)%mod=(a*b^(mod-2))%mod,mod为素数
  原理是费马小定理:a^(mod-1)%mod=1,又a^0%mod=1,a^(mod-1)%mod=a^0%mod,两边同时乘a^(-1),所以a^(-1)=a^(mod-2),推出a/b=a*b^(-1)=a*b^(mod-2)

//质因数分解模板
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int MAXN = 2000000;
int prime[MAXN+1];
void getPrime()//求素数{
    memset(prime,0,sizeof(prime));
    for(int i = 2;i <= MAXN;i++){
        if(!prime[i])prime[++prime[0]] = i;
        for(int j = 1;j <= prime[0] && prime[j] <= MAXN/i;j++){
            prime[prime[j]*i] = 1;
            if(i % prime[j] == 0)break;
        }
    }
}
int factor[100][2];//factor[i][0]存素因子,factor[i][1]存素因子的个数
int fatCnt;//不重复的素因子个数
int getFactors(long long x)
{
    fatCnt = 0;
    long long tmp = x;
    for(int i = 1; prime[i] <= tmp/prime[i];i++)
    {
        factor[fatCnt][1] = 0;
        if(tmp % prime[i] == 0 )
        {
            factor[fatCnt][0] = prime[i];
            while(tmp % prime[i] == 0)
            {
                factor[fatCnt][1] ++;
                tmp /= prime[i];
            }
            fatCnt++;
        }
    }
    if(tmp != 1)
    {
        factor[fatCnt][0] = tmp;
        factor[fatCnt++][1] = 1;
    }
    return fatCnt;
}
int main()
{ 
    getPrime();
    int x;
    scanf("%d",&x);
    getFactors(x);    
    return 0;
}
//筛素数
const int MAXN = 1000000;
int prime[MAXN+1];
void getPrime()
{
    memset(prime,0,sizeof(prime));
    for(int i = 2;i <= MAXN;i++)
    {
        if(!prime[i])prime[++prime[0]] = i;
        for(int j = 1;j <= prime[0] && prime[j] <= MAXN/i;j++)
        {
            prime[prime[j]*i] = 1;
            if(i % prime[j] == 0)break;
        }
    }
}
//long long 数的素数判定+质因数分解
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<algorithm>
using namespace std;
typedef long long ll;
const int S=20;//随机算法判定次数,S越大判错概率越小
//计算(a*b)%c;a,b,c<2^63
ll mult_mod(ll a,ll b,ll c){
    a%=c;
    b%=c;
    ll ret=0;
    while(b){
        if(b&1){
            ret+=a;
            ret%=c;
        }
        a<<=1;
        if(a>=c) a%=c;
        b>>=1;
    }
    return ret;
}
//计算(x^n)%c
ll pow_mod(ll x,ll n,ll c){
    if(n==1) return x%c;
    x%=c;
    ll tmp=x;
    ll ret=1;
    while(n){
        if(n&1) ret=mult_mod(ret,tmp,c);
        tmp=mult_mod(tmp,tmp,c);
        n>>=1;
    }
    return ret;
}
//以a为基,n-1=x*2^t      a^(n-1)=1(mod n)  验证n是不是合数
//一定是合数返回true,不一定返回false
bool check(ll a,ll n,ll x,ll t){
    ll ret=pow_mod(a,x,n);
    ll last=ret;
    for(int i=1;i<=t;i++){
        ret=mult_mod(ret,ret,n);
        if(ret==1&&last!=1&&last!=n-1) return true;
        last=ret;
    }
    if(ret!=1) return true;
    return false;
}
// Miller_Rabin()算法素数判定
//是素数返回true.(可能是伪素数,但概率极小)
//合数返回false;
bool Miller_Rabin(ll n){
    if(n<2) return false;
    if(n==2) return true;
    if((n&1)==0) return false;
    ll x=n-1;
    ll t=0;
    while((x&1)==0){
        x>>=1;
        t++;
    }
    for(int i=0;i<S;i++){
        ll a=rand()%(n-1)+1;
        if(check(a,n,x,t)) return false;
    }
    return true;
}
ll gcd(ll a,ll b){
    if(a==0) return 1;
    if(a<0) return gcd(-a,b);
    while(b){
        ll t=a%b;
        a=b;
        b=t;
    }
    return a;
}
//Pollard_rho质因数分解算法
ll factor[1000];//质因数分解结果(无序的)
int tot;//质因数的个数,数组下标从0开始
ll Pollard_rho(ll x,ll c){
    ll i=1,k=2;
    ll x0=rand()%x;
    ll y=x0;
    while(1){
        i++;
        x0=(mult_mod(x0,x0,x)+c)%x;
        ll d=gcd(y-x0,x);
        if(d!=1&&d!=x) return d;
        if(y==x0) return x;
        if(i==k){
            y=x0;
            k+=k;
        }
    }
}
//对n进行素因子分解
void findfac(ll n){
    tot=0;
    if(Miller_Rabin(n)){//素数
        factor[tot++]=n;
        return;
    }
    ll p=n;
    while(p>=n)
        p=Pollard_rho(p,rand()%(n-1)+1);
    findfac(p);
    findfac(n/p);
}
int main()
{
    return 0;
}
//欧拉函数是积性函数即 phi(ab) = phi(a) * phi(b) (a与b互质);
//1~n中与n互质的整数和为 n * phi(n) / 2 (n > 1);
//sigma(d|n)phi(d) = n;
//质数p和正整数k : phi(p^k) = p^k - p^(k - 1) = (p - 1) * p^(k - 1);
//
//
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
const int MAXN=1000000;
ll c[100];
int n,prime[MAXN+10],mu[MAXN+10],phi[MAXN+10],tot;
bool check[MAXN+10];
//组合
//性质:c(n,k)+c(n,k+1)=c(n+1,k+1);
//根据c(n,k+1)=c(n,k)*(n-k)/(k+1) 可以O(n)算出所有的。
void getC(){
    c[0]=1;
    for(int i=0;i<n;i++)
        c[i+1]=c[i]*(n-i)/(i+1);
}
//扩展欧几里得
void kgcd(ll a,ll b,ll &d,ll &x,ll &y) {
    if(!b){
        d=a; x=1;y=0;
    }else{
        kgcd(b,a%b,d,y,x);
        y-=x*(a/b);
    }
}
//计算模m下a的逆,如果不存在返回-1;
ll inv(ll a,ll m) {
    ll d,x,y;
    kgcd(a,n,d,x,y);
    return d==1 ? (x+n)%n : -1;
}
//线筛素数
void get_prime(){
    memset(check,0,sizeof(check));
    tot=0;
    for(int i=2;i<=MAXN;i++){
        if(!check[i]) prime[tot++]=i;
        for(int j=0;j<tot;j++){
            if(i*prime[j]>MAXN) break;
            check[i*prime[j]]=1;
            if(i%prime[j]==0) break;
        }
    }
}
//线筛欧拉函数
void get_phi(){
    memset(check,0,sizeof(check));
    phi[1]=1;
    tot=0;
    for(int i=2;i<=MAXN;i++){
        if(!check[i]){
            prime[tot++]=i;
            phi[i]=i-1;
        }
        for(int j=0;j<tot;j++){
            if(i*prime[j]>MAXN) break;
            check[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]*(prime[j]-1);
            }
        }
    }
}
//线筛莫比乌斯函数
void get_mu(){
    memset(check,0,sizeof(check));
    mu[1]=1;
    tot=0;
    for(int i=2;i<=MAXN;i++){
        if(!check[i]){
            prime[tot++]=i;
            mu[i]=-1;
        }
        for(int j=0;j<tot;j++){
            if(i*prime[j]>MAXN) break;
            check[i*prime[j]]=1;
            if(i%prime[j]==0){
                mu[i*prime[j]]=0;
                break;
            }else{
                mu[i*prime[j]]=-mu[i];
            }
        }
    }
}
int main()
{
    return 0;
}
原文地址:https://www.cnblogs.com/--ZHIYUAN/p/6090818.html