數論四大定理小結(初級)

回顧:

數論四大定理

威爾遜定理

若p爲質數,則p可整除(p-1)!+1。


歐拉定理(也稱費馬-歐拉定理)
若n,a爲正整數,且n,a互素,(a,n) = 1,則

a^φ(n) ≡ 1 (mod n)


孫子定理(又稱中國剩餘定理)
公元前後的《孫子算經》中有“物不知數”問題:“今有物不知其數,三三數之餘二 ,五五數之餘三 ,七七數之餘二,問物幾何?”答爲“23”。
明朝程大位用歌謠給出了該題的解法:“三人同行七十稀,五樹梅花廿一枝,七子團圓月正半,除百零五便得知。”

以現代的說法,是找出三個關鍵數70,21,15。解法的意思就是用70乘3除所得的餘數,21乘5除所得的餘數,15乘7除所得的餘數,然後總加起來,除以105的餘數就是答案。


費馬小定理
假如p是質數,且(a,p)=1,那麼 a^(p-1) ≡1(mod p)。

假如p是質數,且a,p互質,那麼 a的(p-1)次方除以p的餘數恆等於1。


1.威爾遜定理 HDU 2973 YAPTCHA

這題就是威爾遜定理的一個簡單應用,由於向下取整的存在,式子的值就‘0’或‘1’。

#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<iomanip>
#include<cstdio>
using namespace std;
inline void RD(int &ret)
{
    char c;
    do
    {
        c=getchar();
    }
    while(c<'0'||c>'9');
    ret=c-'0';
    while((c=getchar())>='0'&&c<='9')
    {
        ret=ret*10+(c-'0');
    }
}
inline void OT(int a)
{
    if(a>=10)
    {
        OT(a/10);
    }
    putchar(a%10+'0');
}
bool f(int x)
{
    int i,n=int(sqrt(double(x)));
    if(x==2||x==3)
    {
        return true;
    }
    for(i=2;i<=n;++i)
    {
        if(x%i==0)
        {
            return false;
        }
    }
    return true;
}
int a[1000001];
void g()
{
    int i;
    a[1]=0;
    for(i=2;i<=1000000;++i)
    {
        if(f(3*i+7)==true)//判斷是否爲素數,而確定前式是否爲整除式
        {
            a[i]=a[i-1]+1;
        }
        else
        {
            a[i]=a[i-1];
        }
    }
}
int main()
{
    int t,n,i;
    g();
    RD(t);
    while(t--)
    {
        RD(n);
        OT(a[n]);
        printf("\n");
    }
    return 0;
}

2.歐拉定理 HDU 1395 2^x mod n = 1

歐拉定理的直接應用,求出n以內與n互質的數量

#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<iomanip>
#include<cstdio>
using namespace std;
inline void RD(int &ret)
{
    char c;
    do
    {
        c=getchar();
    }
    while(c<'0'||c>'9');
    ret=c-'0';
    while((c=getchar())>='0'&&c<='9')
    {
        ret=ret*10+(c-'0');
    }
}
inline void OT(int a)
{
    if(a>=10)
    {
        OT(a/10);
    }
    putchar(a%10+'0');
}
int main()
{
    int n,sum,i;
    while(scanf("%d",&n)!=EOF)
    {
        if(n==1||n%2==0)
        {
            printf("2^? mod %d = 1\n",n);
        }
        else
        {
            sum=1;
            for(i=1;i<5001;++i)//求互質數
            {
                sum*=2;
                sum%=n;
                if(sum==1)
                {
                    break;
                }
            }
            printf("2^%d mod %d = 1\n",i,n);
        }
    }
    return 0;
}


3.孫子定理 HDU 3579 Hello Kiki

孫子定理的一般應用,由於存在不可能的情況,所以不建議使用直接暴搞,應使用擴展歐幾里得公式,求出初等公式,在一步步求解。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
inline void RD(int &ret)
{
    char c;
    do
    {
        c=getchar();
    }
    while(c<'0'||c>'9');
    ret=c-'0';
    while((c=getchar())>='0'&&c<='9')
    {
        ret=ret*10+(c-'0');
    }
}
inline void OT(int a)
{
    if(a>=10)
    {
        OT(a/10);
    }
    putchar(a%10+'0');
}
int ext_gcd(int a,int b,int& x,int& y)//擴展歐幾里德
{
    int t,ret;
    if (!b)
    {
        x=1,y=0;
        return a;
    }
    ret=ext_gcd(b,a%b,x,y);
    t=x,x=y,y=t-a/b*y;
    return ret;
}
int main()
{
    int i,t,n,cas=0,f,m1,m2,a1,a2,z,x,y,j,m[11],a[11];
    RD(t);
    while(t--)
    {
        cas++;
        RD(n);
        for(i=0; i<n; i++)
        {
            RD(m[i]);
        }
        for(i=0; i<n; i++)
        {
            RD(a[i]);
        }
        f=0;
        m1=m[0];
        a1=a[0];
        for(i=1; i<n; i++)//求遞推式
        {
            m2=m[i];
            a2=a[i];
            z=ext_gcd(m1,m2,x,y);
            if((a2-a1)%z)
            {
                f=1;
                break;
            }
            j=m2/z;
            x=(x*(a2-a1))/z;
            x=(x%j+j)%j;
            a1=m1*x+a1;
            m1=(m1*m2)/z;
            a1=(a1%m1+m1)%m1;
        }
        if(f==1)
        {
            a1=-1;
        }
        if(a1==0&&n>1)
        {
            a1=m1;
        }
        if(a1==0&&n==1)
        {
            a1=m[0];
        }
        printf("Case %d: %d\n",cas,a1);
    }
    return 0;
}


4.費馬小定理 HDU 4196 Remoteland

一道費馬小定理的變型題,要求n以內包括n的數相乘組成一個最大的完全平方數,需要先通過唯一分解定理將N!(必爲最大)分解爲質因數的相應次冪相乘,由於要得到的是完全平方數,所以需要除去次冪數爲奇數的質因數(除1次)。最後可以轉化爲MAX(n)=(n!*b^(mod-2))%mod。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#define N 1000000007
#define M 10000001
using namespace std;
__int64 b[M];
int a[M],m;
inline void RD(int &ret)
{
    char c;
    do
    {
        c=getchar();
    }
    while(c<'0'||c>'9');
    ret=c-'0';
    while((c=getchar())>='0'&&c<='9')
    {
        ret=ret*10+(c-'0');
    }
}
inline void OT(int a)
{
    if(a>=10)
    {
        OT(a/10);
    }
    putchar(a%10+'0');
}
void f()//求N!,求質因數表
{
    int i,j;
    b[0]=1;
    for(i=1;i<M;++i)
    {
        b[i]=b[i-1]*i%N;
    }
    int x=sqrt(M*1.0);
    for(i=2;i<=x;++i)
    {
        if(!a[i])
        {
            for(j=i*i;j<M;j+=i)
            {
                a[j]=1;
            }
        }
    }
    for(i=2;i<M;++i)
    {
        if(!a[i])
        {
            a[m++]=i;
        }
    }
}
__int64 p(__int64 x,__int64 y)//快速冪取模
{
    __int64 res=1;
    while(y>0)
    {
        if(y%2==1)
        {
            res=(res*x)%N;
        }
        x=(x*x)%N;
        y/=2;
    }
    return res;
}
int main()
{
    f();
    int n,i,tmp,tsp;
    __int64 ans,sum;
    while(scanf("%d",&n))
    {
        if(n==0)
        {
            break;
        }
        sum=1;
        for(i=0;i<m&&a[i]<=n;++i)
        {
            tmp=n;
            tsp=0;
            while(tmp)
            {
                tsp+=(tmp/=a[i]);
            }
            if(tsp%2==1)
            {
                sum=sum*a[i]%N;
            }
        }
        ans=b[n]*p(sum,N-2)%N;//費馬小定理
        printf("%I64d\n",ans);
    }
    return 0;
}

陸續還有總結,敬請期待~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章