• 数论模版


     

     

    一. 扩展的欧几里德和不定方程的解

    解不定方程ax  +  by  =  n的步骤如下:  

     

    (1)计算gcd(a,  b).  若gcd(a,  b)不能整除n,则方程无整数解;否则,在方程的两边同除以gcd(a,  b),得到新的不定方程a'x  +  b'y  =  n',此时gcd(a',  b')  =  1  

     

    (2)求出不定方程a'x  +  b'y  =  1的一组整数解x0,  y0,则n'x0,n'y0是方程a'x  +  b'y  =  n'的一组整数解。  

     

    (3)根据扩展欧几里德定理,可得方程a'x  +  b'y  =  n'的所有整数解为:  

    x  =  n'x0  +  b't  

    y  =  n'y0  -  a't  

    (t为整数)  

    这也就是方程ax  +  by  =  n的所有整数解  

     

    利用扩展的欧几里德算法,计算(a,  b)和满足gcd  =  (a,  b)  =  ax0  +  by0的x0和y0,也就是求出了满足a'x0  +  b'y0  =  1的一组整数解。因此可得:  

    x  =  n/gcd  *  x0  +  b/gcd  *  t  

    y  =  n/gcd  *  y0  -  a/gcd  *  t  

    (t是整数) 

     

    int extend_Euclid(int a, int b, int &x, int &y)

    {

        if (b == 0){

            x = 1;

            y = 0;

            return a;

        }

        int gcd= extend_Euclid ( b, a % b, x, y ); 

        int temp = x;

        x = y;

        y = temp - (a / b) * y;

        return gcd;

    }

     

    二. 中国同余定理

    Poj 2891

     

    #include<stdio.h>

    #include<iostream>

    using namespace std;

    __int64 GCD(__int64 i,__int64 j)

    {

        if(j==0)

            return i;

        else

            return GCD(j,i%j);

    }

    __int64 extend_Euclid(__int64 a, __int64 b, __int64 &x, __int64 &y)

    {

        if (b == 0){

            x = 1;

            y = 0;

            return a;

        }

        __int64 gcd= extend_Euclid ( b, a % b, x, y ); 

        __int64 temp = x;

        x = y;

        y = temp - (a / b) * y;

        return gcd;

    }

    //只有两个式子的中国同余定理,return z=a*xx+x=b*yy+y;

    __int64 CRT_2(__int64 a,__int64 x,__int64 b,__int64 y)

    {

        __int64 xx,yy,gcd;

        gcd=extend_Euclid(a,b,xx,yy);

        __int64 c=y-x;

        while(c<0)

            c+=a;

        if(c%gcd!=0)

            return -1;

        xx*=c/gcd;

        yy*=c/gcd;

        __int64 t=yy/(a/gcd);

        while(yy-t*(a/gcd)>0)

            t++;

        while(yy-(t-1)*(a/gcd)<=0)

            t--;

        return (t*(a/gcd)-yy)*b+y;

    }    

    //chinese remainder theorem  

    //crt[i][0]存的是除数,crt[i][1]存的是余数,0<=i<n,n>1,返回结果,-1表示无解 

    __int64 CRT(__int64 crt[][2],int n)

    {

        __int64 m=crt[0][0]/GCD(crt[0][0],crt[1][0])*crt[1][0];

        __int64 ans=CRT_2(crt[0][0],crt[0][1],crt[1][0],crt[1][1])%m;

        for(int i=2;i<n&&ans!=-1;i++){

            ans=CRT_2(m,ans,crt[i][0],crt[i][1]);

            m*=crt[i][0]/GCD(m,crt[i][0]);

            ans%=m;

        }    

        return ans;

    }    

    int main(void)

    {

        int n;

        __int64 a[10000][2];

        while(scanf("%d",&n)==1){

            for(int i=0;i<n;i++)

                scanf("%I64d%I64d",&a[i][0],&a[i][1]);

            if(n==1)

                printf("%I64d\n",a[0][1]);

            else

                printf("%I64d\n",CRT(a,n));

        }

        return 0;

    }

     

    三. 原根

    Poj 1284    ans=φ(p-1);//p是素数

     

    设h为一整数,n为一正整数,(h,n)=k,适合h^k=1(mod n)的最小正整数k叫做h对n的次数。如果k=φ(n),则此时h被称为模n的原根。1773年,欧拉证明了素数P有原根。1785年,勒让德证明:设k|(p-1),恰有φ(k)个模p互不同余的数对模p的次数为k。

     

    大家可以去搜索一下“二次剩余”

     

    p是奇素数,如果{xi%p | 1 <= i <= p - 1} = {1,2,...,p-1},则称x是p的原根.

    给出一个p,问它的原根有多少个.

     {xi%p | 1 <= i <= p - 1} = {1,2,...,p-1} 等价于 {xi%(p-1) | 1 <= i <= p - 1} = {0,1,2,...,p-2},即为(p-1)的完全剩余系

    若x,x2...x(p-1)是(p-1)的完全剩余系,

    根据定理,可以推出若gcd(x, p-1) = 1时, (1,x,...,x(p-2))也是(p-1)的完全剩余系

    因为若xi != xj (mod p-1),那么x*xi != x*xj (mod p-1),与条件m矛盾,所以 xi = xj (mod p-1),

    由此可以确定答案为EulerPhi(p-1)

    有误之处请指出.. 

     

     

    (拉格朗日四平方和定理)

      每个自然数均可表示成4个平方数之和。3个平方数之和不能表示形式如4k(8n+ 7)的数。 如果在一个正整数的因数分解式中,没有一个数有形式如4k+3的质数次方,该正整数可以表示成两个平方数之和。

     

    四. 积性函数

    在非数论的领域,积性函数指所有对于任何a,b都有性质f(ab)=f(a)f(b)的函数。

    而本条目只讨论在数论中的积性函数。对于正整数n的一个算术函数 f(n),当中f(1)=1且当a,b互质,f(ab)=f(a)f(b),在数论上就称它为积性函数。若某算术函数f(n)符合f(1)=1,且就算a,b不互质,f(ab)=f(a)f(b),则称它为完全积性的。

     

    积性函数的值完全由质数的幂决定,这和算术基本定理有关。即是说,若将n表示成质因数分解式如  N=p1^a1*p2^a2..pk^ak

    则 f(N)=f(p1^a1)*f(p2^a2)*…f(pk^ak)

    f为积性函数且f(p^n) = f(p)^n,则f为完全积性函数。

     

    例子:

    φ(n) -欧拉φ函数,计算与n互质的正整数之数目 

    μ(n) -默比乌斯函数,关于非平方数的质因子数目 

    gcd(n,k) -最大公因数,当k固定的情况 

    d(n) n的正因数数目 

    σ(n) n的所有正因数之和 

    σk(n): 因数函数,n的所有正因数的k次幂之和,当中k可为任何复数。在特例中有: 

    σ0(n) = d(n) 及 

    σ1(n) = σ(n) 

    1(n) -不变的函数,定义为 1(n)=1 (完全积性) 

    Id(n) -单位函数,定义为 Id(n)=n (完全积性) 

    Idk(n) -幂函数,对于任何复数、实数k,定义为Idk(n) = n^k (完全积性) 

    Id0(n) = 1(n) 及 

    Id1(n) = Id(n) 

    ε(n) -定义为:若n = 1,ε(n)=1;若n > 1,ε(n)=0。有时称为“对于狄利克雷卷积的乘法单位”(完全积性) 

    (n/p) -勒让德符号,p是固定质数(完全积性) 

    λ(n) -刘维尔函数,关于能整除n的质因子的数目 

    γ(n),定义为γ(n)=(-1)^ω(n),在此加性函数ω(n)是不同能整除n的质数的数目 

    所有狄利克雷特征均是完全积性的

     

    加性函数:

    在非数论的领域,加性函数指有对于任何a,b都有性质f(ab)=f(a)+f(b)的函数。

    而本条目只讨论在数论中的加性函数。对于正整数n的一个算术函数f(n),当中f(1)=1且当a,b互质,f(ab)=f(a)+f(b),在数论上就称它为加性函数。若某算术函数f(n)就算a,b不互质,f(ab)=f(a)+f(b),称它为完全加性的。

     

    Ω(n)n的所有质因子数目。特别的是因为1无任何质因子,Ω(1)=0。 

    ω(n)n的相异质因子数目 

    a0(n)(或称sopfr(n))—所有n的质因子之和 

    a1(n)(或称sopf(n))—所有n的不同质因子之和

    五. 欧拉函数性质

    在数论中,对正整数n,欧拉函数是小于或等于n的正整数中与n互质的数的数目。此函数以其首名研究者欧拉命名,它又称为φ函数、欧拉商数等。

    例如,因为1,3,5,7均和8互质。

    欧拉函数实际上是模n的同余类所构成的乘法群(即环的所有单位元组成的乘法群)的阶。这个性质与拉格朗日定理一起构成了欧拉定理的证明。

     

    phi(n)<=n;   phi(1)=1;  phi(p)=p-1;

     

     

     

    phi(p^n)=(p-1)*p^(n-1);

    phi(m*n)=phi(m)*phi(n);  gcd(n,m)=1;

    (m,k)=1, k^phi(m)=1(modm);

     

     

     

     

    六. 线性求1-max的欧拉函数值

    Poj 2478   O(n)求素数,求欧拉函数(1-MAX

    #include<iostream>

    using namespace std;

    const int MAX=1001000;

    int pri[MAX/3],pn=0;

    char notp[MAX]={0};

    int phi[MAX];

    __int64 sum[MAX];

    void phif(void)

    {

        for(int i=2;i<MAX;i++){

            if(notp[i]==0){

                pri[pn++]=i;

                phi[i]=i-1;

            }

            for(int j=0;j<pn&&MAX>pri[j]*i;j++){

                notp[i*pri[j]]=1;

                if(i%pri[j]==0){

                    phi[i*pri[j]]=phi[i]*pri[j];

                    break;

                }

                else

                    phi[i*pri[j]]=phi[i]*phi[pri[j]];

            }

        }

    }

    int main(void)

    {

        phif();

        int n;

        sum[2]=phi[2];

        for(int i=3;i<=1000000;i++)

            sum[i]=sum[i-1]+phi[i];

        while(1){

            scanf("%d",&n);

            if(n==0)

                break;

            printf("%I64d\n",sum[n]);

        }

        return 0;

    }

    七. 求单个欧拉函数,求最小的x(phi(n)%x==0),使得2^x =1(mod n)

    Poj3358,n/m表示成2进制小数的循环节起始位和长度。

    #include<iostream>

    using namespace std;

    int p[100000],pn=0;

    char pp[1000000]={0};

    void pf(void)

    {

        for(int i=2;i<1000000;i++){

            if(pp[i]==0){

                p[pn++]=i;

                for(int j=i;i<1000&&i*j<1000000;j++)

                    pp[i*j]=1;

            }    

        }    

        //printf("%d\n",pn);

    }    

    __int64 phif(__int64 n)

    {

        __int64 k=n;

        for(int i=0;i<pn&&k!=1&&(__int64)p[i]*p[i]<=k;i++){

            if(k%p[i]==0){

                n-=n/p[i];

                while(k%p[i]==0)

                    k/=p[i];

            }    

        }    

        if(k!=1)

            n-=n/k;

        return n;

    }    

    __int64 pm[100];

    //pm[i]=d^(1<<i)%m; n=d^k%m

    __int64 pow_mod(__int64 d,__int64 k,__int64 m)

    {

        if(pm[0]==-1){

            pm[0]=d%m;

            for(int i=1;i<100;i++)

                pm[i]=pm[i-1]*pm[i-1]%m;

        }    

        __int64 n=1;

        for(int i=0;k>0;i++){

            if(k&1==1){

                n*=pm[i];

                n%=m;

            }    

            k>>=1;

        }    

        return n;

    }     

    __int64 GCD(__int64 x,__int64 y)

    {

        if(x==0)

            return y;

        else

            return GCD(y%x,x);

    }    

    int main(void)

    {

        pf();

        int cas=1;

        __int64 k,n,m,ans0,ans1,phn;

        while(scanf("%I64d/%I64d",&m,&n)!=EOF){

            k=GCD(m,n);

            m/=k;

            n/=k;

            for(ans0=1;n%2==0;ans0++,n>>=1);

            m=phif(n);

            k=m;

            pm[0]=-1;//还原 

            for(int i=0;i<pn&&k>1;i++){

                if(k%p[i]==0){

                    while(k%p[i]==0)

                        k/=p[i];

                    while(m%p[i]==0&&pow_mod(2,m/p[i],n)==1)

                        m/=p[i];

                }    

            }    

            printf("Case #%d: %I64d,%I64d\n",cas++,ans0,m);

        }    

        system("pause");

        return 0;

    }

     

    语法:result=GCD(long long i,long long j);

    参数:

    i,j

    返回值:

     GCD(i,j)

    注意:

     

     

    源程序:

     

     

    long long GCD(long long i,long long j)

    {

        if(j==0)

            return i;

        else

            return GCD(j,i%j);

    }

     

     

    语法:result=GCD(long long i,long long j);

    参数:

    gcd(a,b)=ax+by*x,*y 

    返回值:

     gcd(a,b),x,y

    注意:*x,*y 

     

    源程序: 

    long long Extend_Euclid(long long a,long long b,long long &x,long long &y)

    {

        if (b == 0){

            x = 1;

            y = 0;

            return a;

        }

        long long gcd= Extend_Euclid ( b, a % b, x, y ); 

        long long temp = x;

        x = y;

        y = temp - (a / b) * y;

        return gcd;

    }

    语法:result=China_Reminder_Therem(long long B[]],long long W[],long long n);

    参数:

    B[]W[]

     a=B[] (mod W[]) 的对应参数,0<=i<n,n>1

    返回值:

     a 的值,如果没有解返回-1 

    注意:

    W[]存的是除数,B[]存的是余数,0<=i<n,n>1,返回结果,-1表示无解 

     

    //其中W[],B[]已知,W[i]>0W[i]W[j]互质a//?我也不清楚 

     

    源程序:

     

     

    long long GCD(long long i,long long j)

    {

        if(j==0)

            return i;

        else

            return GCD(j,i%j);

    }

    long long Extend_Euclid(long long a,long long b,long long &x,long long &y)

    {

        if (b == 0){

            x = 1;

            y = 0;

            return a;

        }

        long long gcd= Extend_Euclid ( b, a % b, x, y ); 

        long long temp = x;

        x = y;

        y = temp - (a / b) * y;

        return gcd;

    }

    //只有两个式子的中国同余定理,return z=a*xx+x=b*yy+y;

    long long China_Reminder_Therem_2(long long a,long long x,long long b,long long y)

    {

        long long xx,yy,gcd;

        gcd=Extend_Euclid(a,b,xx,yy);

        long long c=y-x;

        while(c<0)

            c+=a;

        if(c%gcd!=0)

            return -1;

        xx*=c/gcd;

        yy*=c/gcd;

        long long t=yy/(a/gcd);

        while(yy-t*(a/gcd)>0)

            t++;

        while(yy-(t-1)*(a/gcd)<=0)

            t--;

        return (t*(a/gcd)-yy)*b+y;

    }    

     

    long long China_Reminder_Theory(long long B[],long long W[],int n)

    {

        long long m=W[0]/GCD(W[0],W[1])*W[1];

        long long ans=China_Reminder_Therem_2(W[0],W[0],W[1],B[1])%m;

        for(int i=2;i<n&&ans!=-1;i++){

            ans=China_Reminder_Therem_2(m,ans,crt[i][0],crt[i][1]);

            m*=W[i]/GCD(m,W[i]);

            ans%=m;

        }    

        return ans;

    }    

  • 相关阅读:
    RPC、HTTP、IDL
    秋招拿了7个offer,分享一些反思和经验
    “功能测试”到“测试开发”升级之路
    Github最全买房租房攻略,火了!
    王垠:怎样尊重一个程序员?
    为什么曾经优秀的人突然变得平庸?
    你这么努力,为什么能力提升还这么慢?
    打工人到什么状态,就可以离职了?
    怎样才能迅速晋升?
    如何做个优秀的经理?
  • 原文地址:https://www.cnblogs.com/jian1573/p/2713520.html
Copyright © 2020-2023  润新知