數論

一個數約數個數=全部素因子的次數+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的逆元ios

  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\n",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;
}
相關文章
相關標籤/搜索