快速幂乘

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

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 __int64
LL 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 7
int 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 9973
int 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 1000007
long 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;
}



	

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







评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值