zoukankan      html  css  js  c++  java
  • 数论板子大总结

    1.欧几里得求gcd

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

    2.扩展欧几里得求解线性方程

    首先根据Bezout定理,对于任意的a,b:ax+by=gcd(a,b);

    然后根据欧几里得求gcd的方法构成等价方程,在递归的同时求出x,y;

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

    另外一种写法:(不只是long long 的事情)

    void exgcd(long long a,long long b,long long& x,long long& y)
    {
    	if(!b){
    		x=1;y=0;
    		return;
    	}
    	exgcd(b,a%b,x,y);
    	long long tmp=x; x=y; y=tmp-a/b*y;
    }
    

    3.扩展欧几里得求逆元

    这其实与上面的求线性方程的本质是一样的,这里就不多说了

    void exgcd(long long a,long long b,long long& x,long long& y)
    {
    	if(!b){
    		x=1;y=0;
    		return;
    	}
    	exgcd(b,a%b,x,y);
    	long long tmp=x; x=y; y=tmp-a/b*y;
    }
    

    4.费马小定理+快速幂求逆元

    long long KSM(long long a,long long b)
    {
    	long long res=1;
    	while(b){
    		if(b&1) res=res*a%p;
    		a=a*a%p;
    		b/=2;
    	}
    	return res;
    }
    
    //inv=KSM(除数,模数-2);
    

    5.线性递推求解逆元

    ki+r0(modp)

    k(r的逆元)+(l的逆元)0(modp)

    (l的逆元)≡k(r的逆元)(modp)

    (l的逆元)≡−⌊p/i​⌋∗((p%i)的逆元)(modp)

    #include <bits/stdc++.h>
    #define p 1000000007
    using namespace std;
    long long inv[100010];
    int main()
    {
    	int n;
    	cin>>n;
    	inv[1]=1;
    	for(int i=2;i<=n;i++){
    		 inv[i]=(p-p/i)*inv[p%i]%p;
    	}
    	for(int i=1;i<=n;i++){
    		cout<<inv[i]<<" ";
    	}
    }
    

    6.高斯消元求解线性方程组

    对于一个未知量xi,找到一个xi的系数非0,但x1~xi-1的系数都是零的方程,然后用初等行变换把其他方程的xi的系数全部消成0;

    在高斯消元完成后,若存在系数都是0,但常数不是0的情况,方程无解;

    通常情况下:一道题并不会直接给出n个n元一次方程组。如果给了n+1个二元方程组,那么我们可以通过相邻两个方程做差,把它变成n个n元一次方程组,然后进行高斯消元求解

    #include <bits/stdc++.h>
    #define eps 1e-8
    using namespace std;
    double a[101][102];
    int n;
    bool GUASS()
    {
    	for(int i=1;i<=n;i++){
    		for(int j=i;j<=n;j++){
    			if(fabs(a[j][i])>eps){
    				for(int k=1;k<=n;k++){
    					swap(a[i][k],a[j][k]);
    				}
    				swap(a[i][n+1],a[j][n+1]);
    				break;
    			}			
    		}
    		for(int j=1;j<=n;j++){
    			if(i==j) continue;
    			double tmp=a[j][i]/a[i][i];
    			for(int k=i;k<=n;k++){
    				a[j][k]-=a[i][k]*tmp;
    			}
    			a[j][n+1]-=a[i][n+1]*tmp;
    		}
    	}
    	for(int i=1;i<=n;i++){
    		bool lala=0;
    		for(int j=1;j<=n;j++){
    			if(a[i][j]!=0){
    				lala=1;
    			}
    		}
    		if(lala==0){
    			cout<<"No Solution";
    			return 0;
    		}
    	}
    	return 1;
    }
    int main()
    {
    	cin>>n;
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=n+1;j++){
    			scanf("%lf",&a[i][j]);
    		}
    	}
    	if(GUASS()){
    		for(int i=1;i<=n;i++){
    			printf("%.2lf
    ",a[i][n+1]/a[i][i]);
    		}
    	}
    }
    

    7.利用高斯消元求取矩阵的逆:
    作用:求X=A/B; (X*B=A,X*B*B的逆矩阵=A*B的逆矩阵,X=A*B的逆矩阵);(任何矩阵*单位矩阵=单位矩阵)

    方法:在读入的n阶矩阵右侧加入一个n阶单位矩阵,然后做高斯消元,使读入的n阶矩阵化为n阶单位矩阵,此时右面加入的矩阵就为所求的逆。

    特点:一个可逆矩阵,它的逆矩阵是唯一的;

    #include <bits/stdc++.h>
    #define p 1000000007
    #define inc(i,a,b) for(register int i=a;i<=b;i++)
    using namespace std;
    int n;
    int a[1000][1000];
    long long KSM(long long a,long long b)
    {
    	long long res=1;
    	while(b){
    		if(b&1) res=res*a%p;
    		a=a*a%p;
    		b/=2;
    	}
    	return res%p;
    }
    int Gauss()
    {
    	inc(i,1,n){
    		inc(j,i,n) if(a[j][i]) {swap(a[j],a[i]);break;}
    		if(a[i][i]==0){cout<<"No Solution"; return 0;}
    		long long tmp=KSM(a[i][i],p-2);
    		inc(j,i,2*n) a[i][j]=a[i][j]*tmp%p;
    		inc(j,1,n){
    			if(i==j) continue;
    			long long tmp2=a[j][i]%p;
    			inc(k,i,2*n) a[j][k]=(a[j][k]-tmp2*a[i][k]%p+p)%p;
    		}
    	}
    	return 1;
    }
    int main()
    {
    	cin>>n;
    	inc(i,1,n){
    		inc(j,1,n) scanf("%d",&a[i][j]);
    		a[i][i+n]=1;
    	}
    	if(Gauss()){
    		inc(i,1,n){
    			inc(j,n+1,2*n){
    				printf("%d ",a[i][j]);
    			}
    			printf("
    ");
    		}
    	}
    } 
    

    8.线性筛质数

    简单的模板

    void prime(int n)
    {
    	int m=0;
        for(int i=2;i<=n;i++){
            if(vis[i]==0){
           	    vis[i]=i;
             	prime[++m]=i;
            }
            for(int j=1;j<=m;j++){
            	if(prime[j]>vis[i]||prime[j]>n/i) break;
            	vis[i*prime[j]]=prime[j];
            }
        }
    }
    

    9.线性筛求解欧拉函数

    特殊的:phi[1]=1;

    phi[n]=phi[n/p]*p(p是质数且p方整除n)

    phi[n]=phi[n/p]*(p-1)(p是质数且p方不整除n)

    void prime(int n)
    {
    	int m=0;
        for(int i=2;i<=n;i++){
            if(vis[i]==0){
           	    vis[i]=i;
             	prime[++m]=i;
             	phi[i]=i-1;
            }
            for(int j=1;j<=m;j++){
            	if(prime[j]>vis[i]||prime[j]>n/i) break;
            	vis[i*prime[j]]=prime[j];
            	phi[i*prime[j]]=phi[i]*(i%prime[j]?prime[j]-1:prime[j]);
            }
        }
    }
    

    10.O(sqrt(n))求解一个数的欧拉函数

    从欧拉函数的定义而来,没什么特别的

    void prime(int n)
    {
    	int m=0;
        for(int i=2;i<=n;i++){
            if(vis[i]==0){
           	    vis[i]=i;
             	prime[++m]=i;
             	phi[i]=i-1;
            }
            for(int j=1;j<=m;j++){
            	if(prime[j]>vis[i]||prime[j]>n/i) break;
            	vis[i*prime[j]]=prime[j];
            	phi[i*prime[j]]=phi[i]*(i%prime[j]?prime[j]-1:prime[j]);
            }
        }
    }
    

    11.欧拉定理的推论求解快速幂

     

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #define ll long long
    using namespace std;
    ll a,m,b;
    inline ll read(ll m){
        register ll x=0,f=0;char ch=getchar();
        while(!isdigit(ch)) ch=getchar();
        while(isdigit(ch)){
            x=x*10+ch-'0';
            if(x>=m) f=1;
            x%=m;ch=getchar();
        }
        return x+(f==1?m:0);
    }
    ll phi(ll n){
        ll ans=n,m=sqrt(n);
        for(ll i=2;i<=m;i++){
            if(n%i==0){
                ans=ans/i*(i-1);
                while(n%i==0) n/=i; 
            }
        }
        if(n>1) ans=ans/n*(n-1);
        return ans;
    }
    ll fast_pow(ll a,ll b,ll p){
        ll ret=1;
        for(;b;b>>=1,a=a*a%p)
            if(b&1) ret=ret*a%p;
        return ret;
    }
    int main()
    {
        cin>>a>>m;
        b=read(phi(m));
        cout<<fast_pow(a,b,m);
        return 0;
    }
    

    12.BSGS求解高次同余方程

    利用了跳过无用枚举的技巧巧妙地将O(nlogn)的算法优化成了O(sqrt(n)logn),并保证了正确性;

    但是map的映射或许会加大程序的常数;

    void BSGS(long long a, long long ans, long long p) {
        map<long long, long long> Myhash;
        ans %= p;
        int tmp = sqrt(p) + 1;
        for (int i = 0; i < tmp; i++) {
            Myhash[(ans * KSM(a, i, p)) % p] = i;
        }
        a = KSM(a, tmp, p) % p;
        if (a == 0 && ans == 0) {
            cout << "1" << endl;
            return;
        }
        if (a == 0 && ans != 0) {
            cout << "Orz, I cannot find x!" << endl;
            return;
        }
        for (int i = 0; i <= tmp; i++) {
            if (Myhash.find(KSM(a, i, p)) != Myhash.end() && (i * tmp - Myhash[KSM(a, i, p)] >= 0)) {
                cout << i * tmp - Myhash[KSM(a, i, p)] << endl;
                return;
            }
        }
        cout << "Orz, I cannot find x!" << endl;
    }
    

      

    updataing......

  • 相关阅读:
    内存溢出
    Spring-bean的循环依赖以及解决方式
    JUC中Lock和ReentrantLock介绍及源码解析
    RocketMQ阅读注意
    RocketMQ环境搭建
    HSF源码阅读
    最近找工作,有招JAVA开发的可以联系我,如果不嫌弃我2年前用C,也可以联系我
    Spring Extensible XML
    MySQL主主+Keepalived架构安装部署
    记录一则数据库死锁故障的分析过程
  • 原文地址:https://www.cnblogs.com/kamimxr/p/11734489.html
Copyright © 2011-2022 走看看