快速幂乘

来源:互联网 发布:淘宝直播海报图片 编辑:程序博客网 时间:2024/05/01 02:12

快速幂乘用的是二分的思想

a^b%c,当b比较大时可将其分解

当b为偶数时,a^b%c=(a^(b/2)*a^(b/2))%c;当b为奇数时,a^b%c=(a^(b/2)*a^(b/2)*a)%c

AOJ-569-乘的更快

http://icpc.ahu.edu.cn/OJ/Problem.aspx?id=569

赤裸裸的快速幂乘

#include<stdio.h>#include<string.h>#include<stdlib.h>#define Mod 99991__int64 ans,x,y;void power(__int64 n){    if(n==0)    {        ans=1;        return;    }    if(n==1)    {        ans=x%Mod;        return;    }    power(n>>1); //二分    ans=((ans%Mod)*(ans%Mod))%Mod;    if(n&1)  //n为奇数时需要多乘一次    {        ans=((ans%Mod)*(x%Mod))%Mod;        return;    }    return;}int main(){    int t;    scanf("%d",&t);    while(t--)    {        scanf("%I64d %I64d",&x,&y);        power(y);        printf("%I64d\n",ans);    }    return 0;}

FZU-1752-A^B mod C

http://acm.fzu.edu.cn/problem.php?pid=1752

这题也是快速幂乘,要注意的是a比较大时,需要将b按二进制分解,否则会溢出

在刘汝佳的黑书上也有简单的介绍


#include<stdio.h>#include<string.h>#include<stdlib.h>#define LL __int64LL mul(LL a,LL b,LL c)  //计算a*b%c,将b按二进制分解{LL res=0;for(;b;b>>=1){if(b&1)  //末位为1{res+=a;while(res>=c)res-=c;}a<<=1;while(a>=c)a-=c;}return res;}LL qmod(LL a,LL b,LL c) //幂乘,将b分解为2进制{LL res=1;for(;b;b>>=1){if(b&1)res=mul(a,res,c);a=mul(a,a,c);}return res;}int main(){LL a,b,c;while(scanf("%I64d%I64d%I64d",&a,&b,&c)!=EOF)printf("%I64d\n",qmod(a%c,b,c));return 0;}

快速幂乘也可以用于矩阵的乘法,还是二分的思想

f(n)=A*f(n-1)+B*f(n-2) (Mathtype中,按住Shift和Ctrl,再按空格键,即可添加空格)

用矩阵乘法递推求得

递推可得,这样只需求

对于,当n为偶数时,

n为奇数时,

HDU-1005-Number Sequence

http://acm.hdu.edu.cn/showproblem.php?pid=1005

这题可用矩阵快速幂乘

#include<stdio.h>#include<string.h>#include<stdlib.h>#define Mod 7int a,b,n;int matrix[2][2];int temp[2][2];void power(int x){int i,j,k;if(x==0){matrix[0][0]=matrix[1][1]=1;matrix[0][1]=matrix[1][0]=0;return;}if(x==1){matrix[0][0]=a%Mod;matrix[0][1]=b%Mod;matrix[1][0]=1;matrix[1][1]=0;return;}power(x>>1); //二分for(i=0;i<=1;i++)   //矩阵乘法for(j=0;j<=1;j++){temp[i][j]=0;for(k=0;k<=1;k++)temp[i][j]+=(matrix[i][k]*matrix[k][j])%Mod;}if(x&1) //x为奇数{matrix[0][0]=(temp[0][0]*a+temp[0][1])%Mod;matrix[0][1]=(temp[0][0]*b)%Mod;matrix[1][0]=(temp[1][0]*a+temp[1][1])%Mod;matrix[1][1]=(temp[1][0]*b)%Mod;return;}for(i=0;i<=1;i++)for(j=0;j<=1;j++)matrix[i][j]=temp[i][j]%Mod;return;}int main(){while(scanf("%d %d %d",&a,&b,&n),a||b||n){if(n==1||n==2){printf("1\n");continue;}power(n-2);printf("%d\n",(matrix[0][0]*1+matrix[0][1]*1)%Mod);}return 0;}

HDU-1579-Tr A

http://acm.hdu.edu.cn/showproblem.php?pid=1575

这题是求矩阵高次幂的对角线之和,也可用矩阵快速幂乘

#include<stdio.h>#include<string.h>#include<stdlib.h>#define Mod 9973int temp[15][15];int matrix[15][15];int a[15][15];int n;void power(__int64 x){int i,j,k;if(x==1){for(i=0;i<n;i++)for(j=0;j<n;j++)matrix[i][j]=a[i][j];    return;}power(x>>1);for(i=0;i<n;i++)for(j=0;j<n;j++){temp[i][j]=0;for(k=0;k<n;k++)temp[i][j]+=((matrix[i][k]*matrix[k][j])%Mod);temp[i][j]%=Mod;   //防止溢出,不加会WA}    if(x&1){        for(i=0;i<n;i++)for(j=0;j<n;j++){matrix[i][j]=0;            for(k=0;k<n;k++)matrix[i][j]+=(temp[i][k]*a[k][j])%Mod;matrix[i][j]%=Mod;}return;}for(i=0;i<n;i++)for(j=0;j<n;j++)matrix[i][j]=temp[i][j];return;}int main(){int i,j,t,sum;__int64 k;scanf("%d",&t);while(t--){scanf("%d %I64d",&n,&k);for(i=0;i<n;i++)for(j=0;j<n;j++){scanf("%d",&a[i][j]);a[i][j]%=Mod;}power(k);sum=0;for(i=0;i<n;i++)sum+=(matrix[i][i]%Mod);printf("%d\n",sum%Mod);}return 0;}

NYOJ-301-递推求值

http://acm.nyist.net/JudgeOnline/problem.php?pid=301

这题也用矩阵幂乘来递推求值,和上题的区别是多了个常数

f(x)=a*f(x-2)+b*f(x-1)+c



构造一个矩阵即可

#include<stdio.h>#include<string.h>#include<stdlib.h>#define Mod 1000007long long a,b,c,f1,f2,n;long long p[3][3];long long temp[3][3];long long matrix[3][3];void init(){p[0][0]=0;p[0][1]=a;p[0][2]=0;p[1][0]=1;p[1][1]=b;p[1][2]=0;p[2][0]=0;p[2][1]=1;p[2][2]=1;}void power(long long m){int i,j,k;if(m==0){    memset(matrix,0,sizeof(matrix));matrix[0][0]=matrix[1][1]=matrix[2][2]=1;    return;}if(m==1){for(i=0;i<=2;i++)for(j=0;j<=2;j++)matrix[i][j]=p[i][j];return;}power(m>>1);for(i=0;i<=2;i++)for(j=0;j<=2;j++){temp[i][j]=0;for(k=0;k<=2;k++)temp[i][j]+=(matrix[i][k]*matrix[k][j])%Mod;}if(m&1){for(i=0;i<=2;i++)for(j=0;j<=2;j++){matrix[i][j]=0;for(k=0;k<=2;k++)matrix[i][j]+=(temp[i][k]*p[k][j])%Mod;}return;}for(i=0;i<=2;i++)for(j=0;j<=2;j++)matrix[i][j]=temp[i][j];return;}int main(){int t;long long ans;scanf("%d",&t);while(t--){    scanf("%lld %lld %lld %lld %lld %lld",&f1,&f2,&a,&b,&c,&n);if(a<0)a+=Mod;if(b<0)b+=Mod;if(c<0)c+=Mod;if(n==1){printf("%lld\n",f1);continue;}if(n==2){printf("%lld\n",f2);continue;}init();power(n-2);ans=((matrix[0][1]*f1)%Mod+(matrix[1][1]*f2)%Mod+(matrix[2][1]*c)%Mod)%Mod;printf("%lld\n",ans);}return 0;}

哎。。。不知道有什么好的方法来编辑公示,都是贴图的,挺麻烦的睡觉







原创粉丝点击