zoukankan      html  css  js  c++  java
  • 数论

    一个数约数个数=所有素因子的次数+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的逆元

      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
    ",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;
    }
  • 相关阅读:
    第8章 对象的容纳
    第 4 章 初始化和清除
    第 3 章 控制程序流程
    maven教程
    使用Eclipse构建Maven项目 (step-by-step)
    将 Maven生成的java项目转化为支持 Eclipse IDE的项目
    eclipse 中修改 M2_REPO的值
    FilenameUtils工具类
    导出excel小结(C#,.NET,Wpf)
    NPOI导出Excel表功能实现(多个工作簿)(备用)
  • 原文地址:https://www.cnblogs.com/--ZHIYUAN/p/6090818.html
Copyright © 2011-2022 走看看