1. 程式人生 > >數學的一些小知識

數學的一些小知識

列舉因子法

bool judge(int n)
{
    if(n==1) return false;
    for(int i=2;i*i<=n;i++)
    {
        if(n%i==0) return false;
        
    }
    return true;
}

 

要把1特判掉。 可以1秒內單次判斷1~10^16以內的任意一個素數是否是素數

素數篩:提前處理1~N的全體素數,後可以直接判斷是否是素數

const int N=1000001;
bool notprime[N];
void init()
{
    notprime[1]=1;
    for(int i=2;i<N;i++)
    {
        if(notprime[i]==false)
        {
            for(int j=i+1;j<N;j=j+i)
            {
                notprime[j]=true;
            }
        }
    }
}

mertens定理

 

https://wenku.baidu.com/view/c167c17931b765ce05081473.html看一波,嗯,這種東西看不懂還是要看的,不求甚解

可以一秒內10^7以內的質數和合數分離開來,接下來讓每個合數只刪除一次

尤拉篩(線性篩)每一個素數只被記錄一次,每一個合數只會被一個唯一的最小素因子標記一次。

https://wenku.baidu.com/view/4881881daaea998fcc220e99.html    原理還是可以看一下的

大致上講:每一個數有唯一的最大因子,被唯一篩去,唯一最大因子*小於等於最小質因子就是對應的合數,且篩全了

用了反證。

const int N=1000001;
bool notprime[N];
int prime[N];
int pn;
void init()
{
    pn=0;
    notprime[1]=1;
    for(int i=2;i<N;i++)
    {
        for(notprime[i]==false)
        {
            prime[pn++]=i;
        }
        for(int j=0;j<pn;j++)
        {
            notprime[prime[j]*i]==true;
            if(i%prime[j]==0) break;
        }
    }
}

 

1秒鐘處理從10^7~10^8

#include<algorithm>裡面有__gcd函式,注意要會用

最大公約數:

設兩數為a、b(a>b),用

表示a,b的最大公約數,r=a (mod b) 為a除以b的餘數,k為a除以b的商,即

。輾轉相除法即是要證明

第一步:令

,則設

第二步:根據前提可知

第三步:根據第二步結果可知,

也是

的因數

第四步:可以斷定

互質(這裡用反證法進行證明:設

,則

,則

,則a與b的一個公約數

,故c非a與b的最大公約數,與前面結論矛盾,因此c也是b與r的最大公約數)從而可知

,繼而

證畢

注:以上步驟的操作是建立在剛開始時

的基礎之上的,即m與n亦互質。

百度上的解釋,海星,不用想了。

int gcd(int a,int b)
{
    if(b==0) return a;
    return gcd(b,a%b);
}

 

多個數求最大公約數

int gcd(int a,int b)
{
    if(b==0) return a;
    return gcd(b,a%b);
}
int multi_gcd(int a[],int n)
{
    int res=gcd(a[0],a[1]);
    for(int i=2;i<n;i++)
    res=gcd(res,a[i]);
    return res;
}

最小公倍數略。

擴充套件歐幾里得演算法:

把這個實現和Gcd的遞迴實現相比,發現多了下面的x,y賦值過程,這就是擴充套件歐幾里德演算法的精髓。

可以這樣思考:

對於a'=b,b'=a%b 而言,我們求得 x, y使得 a'x+b'y=Gcd(a',b')

由於b'=a%b=a-a/b*b (注:這裡的/是程式設計語言中的除法)

那麼可以得到:

a'x+b'y=Gcd(a',b') ===>

bx+(a - a / b * b)y = Gcd(a', b') = Gcd(a, b) ===>

ay +b(x - a / b*y) = Gcd(a, b)

因此對於a和b而言,他們的相對應的p,q分別是 y和(x-a/b*y)

使用擴充套件歐幾里德演算法解決不定方程的辦法

對於不定整數方程pa+qb=c,若 c mod Gcd(a, b)=0,則該方程存在整數解,否則不存在整數解。

有種較為不嚴謹的方法證明,不過至少彌補了一點空白,望某些數論大師補充修改:

由於我們知道,存在一組x與y使得a*x+b*y=gcd(a,b)。

將等式兩邊同時乘以整數k,即a*x*k+b*y*k=gcd(a,b)*k。如果c mod gcd(a,b)=f,則0<=f<gcd(a,b)。

那麼可以令c=gcd(a,b)*k+f。這樣一來,就有a*x*k+b*y*k+f=c。

若f

0,由於f<gcd(a,b)<=a<=b(假設a<=b),所以不存在f=a*m(m為整數),也就不存在a*(x*k+m)+b*y*k=c。也就是說,不存在a*x+b*y=c的整數解x與y。

所以f=0,即只有當c mod gcd(a,b)=0時,a*x+b*y=c有正整數解。得證。

上面已經列出找一個整數解的方法,在找到p * a+q * b = Gcd(a, b)的一組解p0,q0後,p * a+q * b = Gcd(a, b)的其他整數解滿足:

p = p0 + b/Gcd(a, b) * t

q = q0 - a/Gcd(a, b) * t(其中t為任意整數)

至於pa+qb=c的整數解,只需將p * a+q * b = Gcd(a, b)的每個解乘上 c/Gcd(a, b) 即可,但是所得解並不是該方程的所有解,找其所有解的方法如下:

在找到p * a+q * b = Gcd(a, b)的一組解p0,q0後,可以

得到p * a+q * b = c的一組解p1 = p0*(c/Gcd(a,b)),q1 = q0*(c/Gcd(a,b)),p * a+q * b = c的其他整數解滿足:

p = p1 + b/Gcd(a, b) * t

q = q1 - a/Gcd(a, b) * t(其中t為任意整數)

p 、q就是p * a+q * b = c的所有整數解。

上面是百度上的https://baike.baidu.com/item/擴充套件歐幾里德演算法/1053275?fr=aladdin比較透徹

int exgcd(int a,int b,int &x,int &y)
{
    if(b==0)
    {
        x=1;y=0;
        return a;
    }
    int d=exgcd(b,a%b,x,y);
    int t=x;
    x=y;
    y=t-a/b*y;
    return d;
}

線性同餘方程,求逆元

int solve(int a,int b,int n)
{
    int d=gcd(a,n);
    if(b%d==0) return -1;
    int k=b/d;
    int x,y;
    exgcd(a,n,x,y);
    return x*k;
}

分解質因數

算術基本定理https://baike.baidu.com/item/算術基本定理/10920095?fr=aladdin

這個寫的通俗易懂,不錯。

預處理素數篩

int p[100];
int e[100];
int cnt;
int fenjie(int n)
{
    cnt=0;
    for(int i=0;i<pn&&prime[i]<=n;i++)
    {
        if(n%prime[i]==0)
        {
            p[cnt]=prime[i];
            while(n%prime[i]==0)
            n/=prime[i];
            e[cnt]++;
            cnt++;
        }
        if(n>1) p[cnt]=n;
        e[cnt++]=1;
    }
}

快速冪

long long pow_mod(long long a,long long n,long long m)
{
    long long res=1;
    while(n>0)
    {
        if(n%2==1) res=res*a%m;
        a=a*a%m;
        n/=2;
    }
    return res;
}

費馬小定理

模素數是有迴圈節的,P-1

int getphi(int n)
{
    int ans=n;
    for(int i=2;i*i<=n;i++)
    {
        if(n%i==0) 
        {
            ans-=ans/i;
            while(n%i==0)
            n/=i;
            
        }
    }
    if(n>1) ans-=ans/n;
    return ans;
}

https://baike.baidu.com/item/尤拉函式

baby step giant stephttps://www.cnblogs.com/wondove/p/7976525.html

不行了,看看其他人部落格吧