zoukankan      html  css  js  c++  java
  • 数论

    矩阵乘法

    可以把矩阵理解为二维数组,数存在里面,矩阵乘法的规则:A*B=C


    实现代码如下:

    const int N=50;
    int c[N][N];
    void multi(int a[N][N],int b[N][N],int n);
    {
        memset(c,0,sizeof(c));
        for(int i=1;i<=n;i++)
        {
            for(int k=1;k<=n;k++)
            {
                if(a[i][k]==0) continue;
                for(int j=1;j<=n;j++)
                {
                    c[i][j]+=a[i][k]*b[k][j];
                }
            }
        }
    
    }
    

    快速幂和矩阵快速幂

    • 利用位运算判断奇偶性
    if(i&1)
    {
        奇数....
    }
    else
    {
        偶数...
    }
    
    • 程序终止问题
      exit(0):正常运行程序并退出程序;

    exit(1):非正常运行导致退出程序;

    return():返回函数,若在主函数中,则会退出函数并返回一值。

    快速幂

    • 快速幂原理
      如果当前的指数是偶数,我们把指数拆成两半,得到两个相同的数,然后把这两个相同的数相乘,可以得到原来的数;
      如果当前的指数是奇数,我们把指数拆成两半,得到两个相同的数,此时还剩余一个底数,把这两个相同的数和剩余的底数这三个数相乘,可以得到原来的数。
    • 当n>0代码如下
    long long res = 1;
    // 进行快速幂运算,n 为当前的指数值,n 为 0 的时候运算结束
    while (n) {
        // 用位运算的方式判断 n 是否为奇数,速度更快,等价于 n%2 
        if (n & 1) {
            // 如果 n 是奇数,那么需要将 x 存入运算结果中
            res *= x;
        }
        // 更新当前的 x 的值
        x *= x;
        // 用位运算的方式进行 n/2,速度更快,等价于 n/=2
        n >>= 1;
    }
    

    完整的代码如下:

    #include <iostream>
    #include <cstdlib>
    using namespace std;
    
    // 使用快速幂求出 x^n 的值并返回,不考虑高精度,请控制参数范围
    double myPow(double x, int n) {
        // 任何不是 0 的数的 0 次幂为 1 
        if (x && n == 0) {
            return 1;
        } else if (x == 0 && n == 0) {
            exit(1);
        }
        // 如果 n 是负数,那么返回结果要进行处理 
        bool judge = false;
        if (n < 0) {
            judge = true;
            n = -n;
        }
    
        double res = 1;
        while (n) {
            // 用位运算的方式判断 n 是否为奇数,速度更快,等价于 n%2 
            if (n & 1) {
                res =res*res%p;
            }
            x = x*x%p;
            // 用位运算的方式进行 n/2,速度更快,等价于 n/=2
            n >>= 1;
        }
        // n 是负数?1.0/res 否则 res 
        if(judge)
        {
            return 1.0/res;
        }
        else
        {
            return res;
        }
    } 
    
    int main() {
        double x;
        int n;
    
        while (cin >> x >> n) {
            cout << myPow(x, n) << endl << endl; 
        } 
    
        return 0;
    } 
    

    矩阵快速幂模板代码如下

    模板题目链接

    
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define MAXN 200
    #define MOD 1000000007
    using namespace std;
    typedef long long ll;
    
    int A[MAXN][MAXN];
    int res[MAXN][MAXN];
    ll tmp[MAXN][MAXN];
    int n; ll k;
    
    void mulit(int a[][MAXN],int b[][MAXN])
    {
        memset(tmp,0,sizeof(tmp));
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                for(int k=1;k<=n;k++)
                {
                    tmp[i][j]=((ll)a[i][k]*b[k][j]%MOD+tmp[i][j])%MOD;
                }
            }
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                a[i][j]=(int)tmp[i][j];
            }
        }
    
    }
    
    void Pow(int a[][MAXN],ll k)
    {
        memset(res,0,sizeof(res));
        for(int i=1;i<=n;i++)
        {
            res[i][i]=1;
        }
        while(k)
        {
            if(k&1)
            {
                mulit(res,a);
            }
        mulit(a,a);
        k>>=1;
        }
        
    }
    int main()
    {
        scanf("%d%lld",&n,&k);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                scanf("%d",&A[i][j]);
            }
        }
        Pow(A,k);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                printf("%d ",res[i][j]);
            }
            cout<<endl;
        }
    }
    
    

    (代码借用了https://blog.csdn.net/wust_zzwh/article/details/52058209)

    利用矩阵快速幂求斐波那契数列

    利用矩阵快速幂求递推数列的关键是找到合适的递推关系式
    如此大佬博客中所推蓝桥杯 算法提高 递推求值(矩阵快速幂)详解
    利用矩阵快速幂求斐波那契数列的模板题链接P1939 【模板】矩阵加速(数列)
    模板题代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define MAXN 200
    #define MOD 1000000007
    #define ll long long
    using namespace std;
    
    ll n;
    ll A[MAXN][MAXN];
    ll B[MAXN][MAXN];
    ll res[MAXN][MAXN];
    ll tmp[MAXN][MAXN];
    
    void mulit(ll a[][MAXN],ll b[][MAXN])
    {
        memset(tmp,0,sizeof(tmp));
        for(int i=1;i<=6;i++)
        {
            for(int j=1;j<=6;j++)
            {
                for(int k=1;k<=6;k++)
                {
                    tmp[i][j]=((a[i][k]*b[k][j])%MOD+tmp[i][j])%MOD;
                }
            }
        }
        for(int i=1;i<=6;i++)
        {
            for(int j=1;j<=6;j++)
            {
                a[i][j]=tmp[i][j];
            }
        }
    }
    
    void pow(ll a[][MAXN],ll k)
    {
        memset(res,0,sizeof(res));
        for(int i=1;i<=6;i++)
        {
            res[i][i]=1;
        }
        
        while(k)
        {
            if(k&1)
            {
                mulit(res,a);
    //			printf("k=%lld
    ",k);
    //		printf("res=%lld
    ",res[1][1]);
            }
            mulit(a,a);
            k>>=1;
        }
    }
    int main()
    {
        scanf("%lld",&n);
        if(n==1||n==2)
        {
            printf("1");
            return 0;
        }
        A[1][1]=1;
        A[1][2]=1;
        A[2][1]=1;
        A[2][2]=0;
        B[1][1]=1;
        B[2][1]=1;
        pow(A,n-2);
    //	cout<<1;
        mulit(res,B);
        
        printf("%lld ",res[1][1]);
        return 0;
    }
     
    

    类似题及代码如下:
    P1939 【模板】矩阵加速(数列)
    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define MAXN 7
    #define MOD 1000000007
    #define ll long long
    using namespace std;
    
    ll n;
    ll A[7][7];
    ll B[7][7];
    ll res[7][7];
    ll tmp[7][7];
    
    void mulit(ll a[][MAXN],ll b[][MAXN])
    {
    	memset(tmp,0,sizeof(tmp));
    	for(int i=1;i<=6;i++)
    	{
    		for(int j=1;j<=6;j++)
    		{
    			for(int k=1;k<=6;k++)
    			{
    				tmp[i][j]=((a[i][k]*b[k][j])%MOD+tmp[i][j])%MOD;
    			}
    		}
    	}
    	for(int i=1;i<=6;i++)
    	{
    		for(int j=1;j<=6;j++)
    		{
    			a[i][j]=tmp[i][j];
    		}
    	}
    }
    
    void pow(ll a[][MAXN],ll k)
    {
    	memset(res,0,sizeof(res));
    	for(int i=1;i<=6;i++)
    	{
    		res[i][i]=1;
    	}
    	
    	while(k)
    	{
    		if(k&1)
    		{
    			mulit(res,a);
    //			printf("k=%lld
    ",k);
    //		printf("res=%lld
    ",res[1][1]);
    		}
    		mulit(a,a);
    		k>>=1;
    	}
    }
    
    int main()
    {
    	ll T;
    	scanf("%lld",&T);
    	while(T--)
    	{
    		scanf("%lld",&n);
    		if(n==1||n==2||n==3)
    		{
    			printf("1
    ");
    			continue;
    		}
    		A[1][1]=1;
    		A[1][2]=0;
    		A[1][3]=1;
    		A[2][1]=1;
    		A[2][2]=0;
    		A[2][3]=0;
    		A[3][1]=0;
    		A[3][2]=1;
    		A[3][3]=0;
    		B[1][1]=1;
    		B[2][1]=1;
    		B[3][1]=1;
    		pow(A,n-2);
    		mulit(res,B);
    		printf("%lld
    ",res[2][1]);
    	}
    }
    

    有一个小结论叫做gcd(F(n),F(m))=F(gcd(n,m))

    P1306 斐波那契公约数
    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define MAXN 9
    #define MOD 100000000
    #define ll long long 
    using namespace std;
    
    ll n,m;
    ll A[MAXN][MAXN];
    ll B[MAXN][MAXN];
    ll res[MAXN][MAXN];
    ll tmp[MAXN][MAXN];
    
    void mulit(ll a[][MAXN],ll b[][MAXN])
    {
    	memset(tmp,0,sizeof(tmp));
    	for(int i=1;i<=5;i++)
    	{
    		for(int j=1;j<=5;j++)
    		{
    			for(int k=1;k<=5;k++)
    			{
    				tmp[i][j]=((a[i][k]*b[k][j])%MOD+tmp[i][j])%MOD;
    			}
    		}
    	}
    	for(int i=1;i<=5;i++)
    	{
    		for(int j=1;j<=5;j++)
    		{
    			a[i][j]=tmp[i][j]; 
    		} 
    	}
    }
    
    void pow(ll a[][MAXN],ll k)
    {
    	memset(res,0,sizeof(res));
    	for(int i=1;i<=5;i++)
    	{
    		res[i][i]=1;
    	}
    	while(k)
    	{
    		if(k&1)
    		{
    			mulit(res,a);
    		}
    		mulit(a,a);
    		k>>=1;
    	}
    }
    
    int main()
    {
    	scanf("%lld%lld",&n,&m);
    	A[1][1]=1;
    	A[1][2]=1;
    	A[2][1]=1;
    	A[2][2]=0;
    	B[1][1]=1;
    	B[2][1]=1;
    	ll num;
    	num=__gcd(n,m);
    //	printf("num=%lld",num);
    	if(num==1||num==2)
    	{
    		printf("1");
    		return 0;
    	}
    	pow(A,num-2);
    	mulit(res,B);
    	printf("%lld",res[1][1]);
    	
    }
    

    乘法逆元

    乘法逆元的几种计算方法
    线性推核心代码如下:

    	inv[1]=1;
    	printf("1
    ");
    	for(int i=2;i<=n;i++)
    	{
    		inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD;
    		printf("%lld
    ",inv[i]); 
    	}
    

    拓展欧几里得算法求乘法逆元代码如下

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    
    using namespace std;
    
    void exgcd(int a,int b,int &x,int &y)
    {
    	if(b==0)
    	{
    		x=1;
    		y=0;
    		return;
    	}
    	else
    	{
    		int tx,ty;
    		exgcd(b,a%b,tx,ty);
    		y=tx-(a/b)*ty;
    		x=ty;
    		return;
    	}
    }
    
    int main()
    {
    	int n,p;
    	scanf("%d%d",&n,&p);
    	for(int i=1;i<=n;i++)
    	{
    		int x,y;
    		exgcd(i,p,x,y);
    		if(x<0)
    		{
    			x=x+p;
    		 } 
    		 printf("%d
    ",x);
    	}
     } 
    

    费马小定理代码如下:

    ll Pow(ll a, ll k)
    {
    	ll res=1;
    	while(k)
    	{
    		if(k&1)
    		{
    			res=res*a%MOD;
    		}
    		a=a*a%MOD;
    		k>>=1;
    	}
    	return res;
    }
    

    模板题链接:P3811 【模板】乘法逆元
    拓展题链接:P2613 【模板】有理数取余
    拓展题代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define ll long long
    #define MAXN 100010 
    
    
    using namespace std;
    const int MOD=19260817; 
    ll a,b;
    char str[MAXN];
    
    ll Pow(ll a,ll k)
    {
        ll res=1;
        while(k)
        {
            
            if(k&1)
            {
                res=res*a%MOD;
            }
            a=a*a%MOD;
            k>>=1;
        }
        return res;
    }
    
    int main()
    {
        
         scanf( "%s", str+1 );
        for( int i = 1, en = (int)strlen( str+1 ); i <= en; ++i )
            a = ( a * 10 + str[i] - '0' ) % MOD;
        scanf( "%s", str+1 );
        for( int i = 1, en = (int)strlen( str+1 ); i <= en; ++i )
            b = ( b * 10 + str[i] - '0' ) % MOD;
        if(b==0)
        {
            printf("Angry!");
            return 0;
        }
        ll ans=(Pow(b,MOD-2)%MOD*a)%MOD;
        printf("%lld",ans);
     } 
    
  • 相关阅读:
    IIS的各种身份验证详细测试
    HTTP Error 401.3 Unauthorized Error While creating IIS 7.0 web site on Windows 7
    C/S and B/S
    WCF ContractFilter mismatch at the EndpointDispatcher exception
    Configure WCF
    Inheritance VS Composition
    Unhandled Error in Silverlight Application, code 2103 when changing the namespace
    Java RMI VS TCP Socket
    Principles Of Object Oriented Design
    Socket处理发送和接收数据包,一个小实例:
  • 原文地址:https://www.cnblogs.com/LITTLESUNwl/p/10953125.html
Copyright © 2011-2022 走看看