NO.4 快速幂或者矩阵快速幂

来源:互联网 发布:录屏软件cs6 编辑:程序博客网 时间:2024/06/06 01:38

快速幂的算法函数:

int pow1(int a, int b){    int ans = 1;    while(b)    {        if(b&1)//相当于b%2==1,位运算,判断二进制最后一位是否为奇数         ans *= a;        a *= a;        b >>= 1;//位运算,将二进制右移一位,相当于b /= 2;    }    return ans;}

快速幂取模:

int pow1(int a, int b, int c)//a的b次方,取模c{    int ans = 1;    a = a % c;//积的取余等于取余的积的取余    while(b)    {        if(b & 1)//相当于b%2==1,位运算,判断二进制最后一位是否为奇数         ans = (ans * a) % c;        a = (a * a) % c;        b >>= 1;//位运算,将二进制右移一位,相当于b /= 2;    }    return ans;}

矩阵的快速幂:

#define MAXN 15#define MOD 10000007typedef long long int LL;LL res[MAXN][MAXN];int N;void M(LL a[MAXN][MAXN], LL b[MAXN][MAXN])//两个矩阵的相乘{    LL ans[MAXN][MAXN];    memset(ans, 0, sizeof(ans));    for(int i=0;i<N;i++)    {        for(int j=0;j<N;j++)        {            for(int k=0;k<N;k++)            {                ans[i][j] = (ans[i][j]+a[i][k]*b[k][j]%MOD)%MOD;            }        }    }    for(int i=0;i<N;i++)    {        for(int j=0;j<N;j++)        {            a[i][j] = ans[i][j];        }    }}void K(LL a[MAXN][MAXN], int n )//矩阵的快速幂{    for(int i=0;i<N;i++)    {        for(int j=0;j<N;j++)        {            //相比数的快速幂,把1变成单位矩阵            res[i][j] = (i==j);//res是单位矩阵        }    }    while(n)    {        if(n&1)             M(res, a);            M(a, a);        n >>= 1;    }}

矩阵的快速幂:
高效计算矩阵的高次方。
简单的入门题目
think:
计算矩阵的高次方,然后取对角线之和。

#include <stdio.h>#include <string.h>#include <algorithm>int k, m;struct S{    int r,c;    int a[15][15];};S ori,res;void init(){    memset(res.a,0,sizeof(res.a));    for(int i=1;i<=10;i++)        res.a[i][i]=1;    for(int i=2;i<=10;i++)        for(int j=1;j<=10;j++)        {            if(i-1!=j)                ori.a[i][j]=0;            else                ori.a[i][j]=1;        }}S maxtri(S x,S y){    S z;    memset(z.a,0,sizeof(z.a));    for(int i=1;i<=10;i++)    {        for(int k=1;k<=10;k++)        {            if(x.a[i][k]==0)                continue;            for(int j=1;j<=10;j++)                z.a[i][j]=(z.a[i][j]+(x.a[i][k]*y.a[k][j])%m)%m;        }    }    return z;}void maxtri_mod(int n){    while(n)    {        if(n&1)            res=maxtri(res,ori);        ori=maxtri(ori,ori);        n>>=1;    }}int main(){    while(scanf("%d%d",&k,&m)!=EOF)    {        for(int i=1;i<=10;i++)            scanf("%d",&ori.a[1][i]);        init();        if(k<=9)        {            printf("%d\n",k%m);            continue;        }        maxtri_mod(k-9);        int sum=0;        for(int i=1;i<=10;i++)        {            sum+=(res.a[1][i]*(10-i))%m;            sum%=m;        }        printf("%d\n",sum%m);    }    return 0;}

A - Jzzhu and Sequences
这算是一道矩阵快速幂的问题,不过有简单方法。

#include<stdio.h>int main(){    int x, m, y;    int a[20];    scanf("%d %d", &x, &y);    a[1]=x;    a[2]=y;    scanf("%d", &m);    //观察发现,此题目有规律,每六组一循环    for(int i=3; i<=6; i++)    {        a[i] = a[i-1] - a[i-2];    }    a[0] = a[6];    printf("%d\n", (((a[m%6]%1000000007)+1000000007)%1000000007));//可能有负数    return 0;}

B - 233 Matrix

#include <stdio.h>#include <stdlib.h>#include <string.h>#define MAXN 15#define MOD 10000007typedef long long int LL;LL res[MAXN][MAXN];int N;void M(LL a[MAXN][MAXN], LL b[MAXN][MAXN]){    LL ans[MAXN][MAXN];    memset(ans, 0, sizeof(ans));    for(int i=0;i<N;i++)    {        for(int j=0;j<N;j++)        {            for(int k=0;k<N;k++)            {                ans[i][j] = (ans[i][j]+a[i][k]*b[k][j]%MOD)%MOD;            }        }    }    for(int i=0;i<N;i++)    {        for(int j=0;j<N;j++)        {            a[i][j] = ans[i][j];        }    }}void K(LL a[MAXN][MAXN], int n){    for(int i=0;i<N;i++)    {        for(int j=0;j<N;j++)        {            res[i][j] = (i==j);        }    }    while(n)    {        if(n&1)             M(res, a);            M(a, a);        n >>= 1;    }}int main(){    int a, b;    LL A[MAXN];    LL AA[MAXN][MAXN];    while(~scanf("%d %d", &a,&b))    {        N = a + 2;        A[0] = 23;        A[a+1] = 3;        memset(AA, 0, sizeof(AA));        for(int i=1;i<=a;i++)            scanf("%lld", &A[i]);        for(int i=0;i<N;i++)        {            if(i!=N-1)                AA[i][0] = 10;            for(int j=1;j<=i;j++)            {                if(i!=N-1)                    AA[i][j] = 1;            }            AA[i][N-1] = 1;        }        K(AA, b);        LL ans = 0;        for(int i=0;i<N;i++)        {            ans = (ans + A[i]*res[N-2][i]%MOD)%MOD;        }        printf("%lld\n", ans);    }    return 0;}