10.1數論初步

10.1.1歐幾里得算法和唯一分解定理

除法表達式

分析:

表達式的值一定可以寫成A/B的形式:A是其中一些Xi的乘積,而B是其他數的乘積,而B是其他數的乘積。不難發現,X2必須放在分母位置,那其他數呢?

其他數均可以放在分子位置

接下來的問題就變成了:判斷E是否爲整數

第一種方法是利用前面介紹的高精度運算:k次乘法加一次除法,正確但是麻煩

第2種方法是利用唯一分解定理,把X2寫成若干素數相乘的形式:

第3種方法是直接約分:每次約掉Xi和X2的最大公約數gcd(Xi,X2),則當且僅當約分結束後X2=1時E爲整數,程序如下

int judge(int* X){
    X[2]/=gcd(X[2],X[1]);
    for(int i=3;i<=k;i++)
        X[2]/=gcd(X[i],X[2]);
    return X[2]==1;
}
整個算法的時間效率取決於這裏的gcd算法。

輾轉相處法的關鍵在於如下恆等式:gcd(a,b)=gcd(b,a mod b).她和邊界條件gcd(a,0)=a一起構成了下面的程序:

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

利用gcd還可以求出兩個整數a,b的最小公倍數lcm(a,b)

不難驗證gcd(a,b)*lcm(a,b)=a*b,不過即使有了公式也不要大意,如果把lcm寫成a*b/gcd(a,b),可能會出錯,因爲a*b會溢出,正確的寫法是先除後乘,即a/gcd(a,b)*b

10.1.2Eratosthenes篩法

無平方因子的數。給出正整數n,m,區間[n,m]內的“無平方因子”的數有多少個?

分析:

對於這樣的限制,直接枚舉判斷會超時:需要判斷10***0個整數,所以需要用Eratosthenes篩法構造1~n的素數表

篩法的思想特別簡單:對於不超過n的每個非負整數p,刪除2p,3p,,,當處理完所有數之後,還沒被刪的就是素數,用VIS[i]表示i已經被刪除

memset(vis,0,sizeof vis);
for(int i=2;i<=n;i++)
    for(j=i*2;j<=n;j+=i)
        vis[j]=1;

10.1.3擴展歐幾里得算法

直線上的點。求直線ax+by+c=0上有多少個整點,滿足x [x1,x2],y [y1,y2]

分析:

在解決這個問題之前,首先學習歐幾里得算法——找出一對整數(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和y的順序變了,而邊界也是不難得出的:gcd(a,0)=1*a-0*0=a.這樣,唯一需要記憶的是y-=x*(a/b),不懂也不要緊。

上面求出了ax+by=gcd(a,b)的一組解(x1,y1),?其他解?任取另外一組解(x2,y2),則ax1+by1=ax2+by2(他們都等於gcd(a,b)),變形得a(x1-x2)=b(y2-y1),近一些列的變形得出

他的任意數解都可以寫成(x0+kB,y0-kA),A=a/gcd(a,b),B=b/gcd(a,b),k取任意整數

。。。。。。

10.1.4同與與模算術

可得下面公式

(a+b)mod n=((a mod n)+(b mod n))mod n

(a-b)mod n=((amodn)-(bmodn)+n)mod n

注意在減法中,由於a mod n可能小於b mod n,需要在結尾上+n,以及乘法過程中可能會溢出

int mul_mod(int a,int b,int n){
    a%=n; b%=n;
    return (int)((long long)a*b%n);
}
分析:

首先,把大數寫成自左向右的形式: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);
這個函數的時間複雜度爲n,當n很大時速度不理想

下利用分治法

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%2==1)
        ans=ans*a%m;
    return (int)ans;
}
//不是很懂





發佈了38 篇原創文章 · 獲贊 2 · 訪問量 8044
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章