【知识学习】快速幂+矩阵快速幂+斐波那契数列及其推广

本文详细介绍了快速幂和矩阵快速幂的原理及应用,并通过不同类型的斐波那契数列问题展示了具体的代码实现。

这一篇blog从有想法到写完所有代码总共花了好长好长时间

虽然最后可能在这篇博文里体现不出来,但是真的好难

快速幂和矩阵快速幂比较简单,稍微带过直接放代码

斐波那契数列才是这次的主角

快速幂

位运算比较快 用了>>和&

LL qpow(LL a , LL b) {
	if(b==0)
		return 1;
	LL c = qpow(a,b>>1)%k;
	if(b&1)
		return c*c%k*a%k;
	return c*c%k;
}

矩阵快速幂

重载一下乘法,再写几个结构体函数,其实其他和快速幂一样

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
typedef long long LL;
#define PI acos(-1)
#define fin freopen("data.txt","r",stdin)
#define INF 2147483647
#define eps 1e-7
#define L 100005
#define mod 76
#define Fo(i,a,b) for(LL i=(a),_=(b); i<=_; i++)
#define Ro(i,b,a) for(LL i=(b),_=(a); i>=_; i--)
inline LL read() {
	LL x=0,f=1;char c=getchar();
    while(!isdigit(c)) {if(c=='-')f=-f;c=getchar();}
    while(isdigit(c)) x=(x<<1)+(x<<3)+(c^48ll),c=getchar();
    return x*f;
}

LL n , k;
struct Mat {
	LL num[105][105];
	Mat() {
		memset(num , 0 , sizeof(num));
	}
	void init() {
		Fo(i,1,n)
			num[i][i] = 1;
	}
	void print() {
		Fo(i,1,n) {
			Fo(j,1,n)
				printf("%d ",num[i][j]);
			printf("\n");
		}	
	}
};
Mat A , E;
Mat operator * (const Mat &x , const Mat &y) {
	Mat z;
	Fo(i,1,n)
		Fo(j,1,n)
			Fo(k,1,n)
				z.num[i][j]=(z.num[i][j]+x.num[i][k]*y.num[k][j]%mod)%mod;
	return z;
}

Mat qpow(Mat x , LL y) {
	if(y==0)
		return E;
	if(y==1)
		return x;
	Mat z = qpow(x , y>>1);
	if(y&1)
		return z*z*x;
	return z*z;
}

int main() {
	E.init();
	n=read();k=read();
	Fo(i,1,n)
		Fo(j,1,n)
			A.num[i][j]=read();
	qpow(A,k).print();
	return 0;
}

斐波那契数列及其推广

有几种形式:(目前遇到的,以下分别标号123)

f [ 1 ] = 1 , f [ 2 ] = 1 , f [ i ] = f [ i − 1 ] + f [ i − 2 ] f[1]=1,f[2]=1,f[i]=f[i-1]+f[i-2] f[1]=1,f[2]=1,f[i]=f[i1]+f[i2]
f [ 1 ] = 1 , f [ 2 ] = 1 , f [ i ] = A × f [ i − 1 ] + B × f [ i − 2 ] f[1]=1,f[2]=1,f[i]=A×f[i-1]+B×f[i-2] f[1]=1,f[2]=1,f[i]=A×f[i1]+B×f[i2]
f [ 1 ] = C , f [ 2 ] = D , f [ i ] = A × f [ i − 1 ] + B × f [ i − 2 ] f[1]=C,f[2]=D,f[i]=A×f[i-1]+B×f[i-2] f[1]=C,f[2]=D,f[i]=A×f[i1]+B×f[i2]

分别对应题目:
LG1720
HDU1005
WIT新生赛J题

第1种

就是常规的斐波那契数列,矩阵快速幂做法如下图

在这里插入图片描述
其实没必要非得用最后一行的公式,用倒数第二行的公式或许更能变通(比如第2种)

代码实现:

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
#include<map>
using namespace std;
typedef long long LL;
#define PI acos(-1)
#define fin freopen("data.txt","r",stdin)
#define INF 2147483647
#define eps 1e-7
#define L 100005
#define mod 1000000007
#define Fo(i,a,b) for(LL i=(a),_=(b); i<=_; i++)
#define Ro(i,b,a) for(LL i=(b),_=(a); i>=_; i--)
#define Ms(a,b) memset((a),(b),sizeof(a))
inline LL read() {
	LL x=0,f=1;char c=getchar();
    while(!isdigit(c)) {if(c=='-')f=-f;c=getchar();}
    while(isdigit(c)) x=(x<<1)+(x<<3)+(c^48ll),c=getchar();
    return x*f;
}

LL n;
struct Mat {
	LL num[6][6];
	Mat() {
		Ms(num,0);
	}
	void init() {
		num[1][1]=num[1][2]=num[2][1]=1;
		num[2][2]=0;
	}
	void E() {
		Fo(i,1,n)
			num[i][i]=1; 
	}
	LL fib() {
		return num[2][1];
	}
};
Mat E , A;

Mat operator * (const Mat &x , const Mat &y) {
	Mat z;
	Fo(i,1,2)
		Fo(j,1,2)
			Fo(k,1,2)
				z.num[i][j]=z.num[i][j]+x.num[i][k]*y.num[k][j];
	return z;
}

Mat qpow(Mat x , LL y) {
	if(!y) return E;
	if(y==1) return x;
	Mat z=qpow(x,y>>1);
	if(y&1)
		return z*z*x;
	return z*z;
}

int main() {
	n=read();
	E.E(); A.init();
	printf("%lld.00",qpow(A,n).fib());
	return 0;
}

第2种

就是第1种的变通(画图有点丑)在这里插入图片描述
代码实现

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
#include<map>
using namespace std;
typedef long long LL;
#define PI acos(-1)
#define fin freopen("data.txt","r",stdin)
#define INF 2147483647
#define eps 1e-7
#define L 100005
#define mod 7
#define Fo(i,a,b) for(LL i=(a),_=(b); i<=_; i++)
#define Ro(i,b,a) for(LL i=(b),_=(a); i>=_; i--)
#define Ms(a,b) memset((a),(b),sizeof(a))
inline LL read() {
	LL x=0,f=1;char c=getchar();
    while(!isdigit(c)) {if(c=='-')f=-f;c=getchar();}
    while(isdigit(c)) x=(x<<1)+(x<<3)+(c^48ll),c=getchar();
    return x*f;
}

LL A , B , n;
struct Mat {
	LL num[15][15];
	Mat() {
		Ms(num,0);
	}
	void init(LL a , LL b) {
		num[1][1]=a; num[1][2]=1;
		num[2][1]=b; num[2][2]=0;
	}
	void K() {
		num[1][1]=num[1][2]=1;
	}
	void E() {
		Fo(i,1,n)
			num[i][i]=1;
	}
	LL fib() {
		return num[1][1]%mod;
	}
};
Mat E , K , P;

Mat operator * (const Mat &x , const Mat &y) {
	Mat z;
	Fo(i,1,2)
		Fo(j,1,2)
			Fo(k,1,2)
				z.num[i][j]=(z.num[i][j]+x.num[i][k]*y.num[k][j]%mod)%mod;
	return z;
}

Mat qpow(Mat x , LL y) {
	if(!y)  return E;
	if(y==1) return x;
	Mat z=qpow(x,y>>1);
	if(y&1)
		return z*z*x;
	return z*z; 
}

int main() {
	E.E(); K.K();
	while(1) {
		A=read(); B=read(); n=read();
		if(A==0&&B==0&&n==0)
			break;
		if(n==1||n==2) {
			printf("1\n");	
			continue;		
		}
		P.init(A,B);
		printf("%lld\n",(K*qpow(P,n-2)).fib()%mod);
	}
	return 0;
}

第3种

这个坑点有点多,但是学到一种求大数的斐波那契数列的方法

就是先求底数矩阵的个位数次方,然后底数矩阵自己求10次方,再做十位依次向前

因为我的做法是求得n-1次方,所以有很大的坑点

所以 直接用n就行!最好别写n-1因为要判断0啥的有亿点点麻烦
在这里插入图片描述

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
#include<map>
using namespace std;
typedef long long LL;
#define PI acos(-1)
#define fin freopen("data.txt","r",stdin)
#define INF 2147483647
#define eps 1e-7
#define L 100005
#define Fo(i,a,b) for(LL i=(a),_=(b); i<=_; i++)
#define Ro(i,b,a) for(LL i=(b),_=(a); i>=_; i--)
#define Ms(a,b) memset((a),(b),sizeof(a))
inline LL read() {
	LL x=0,f=1;char c=getchar();
    while(!isdigit(c)) {if(c=='-')f=-f;c=getchar();}
    while(isdigit(c)) x=(x<<1)+(x<<3)+(c^48ll),c=getchar();
    return x*f;
}

string n;
LL A , B , C , D , mod , len , num[500005] , flag;

struct Mat {
	int num[10][10];
	Mat() {
		Ms(num,0);
	}
	void K(LL a , LL b) {
		num[1][1]=a; num[1][2]=b;
		num[1][3]=num[2][1]=num[3][3]=1;
	} 
	void P(LL f0 , LL f1 , LL f2) {
		num[1][1]=f2;
		num[1][2]=num[2][1]=f1;
		num[2][2]=f0;
		num[3][1]=num[3][2]=num[3][3]=7;
	}
	void E() {
		Fo(i,1,3)
			num[i][i]=1;
	}
	LL fib() {
		return num[1][1]%mod;
	}
};
Mat K , P , ans;

Mat operator * (const Mat &x , const Mat &y) {
	Mat z;
	Fo(i,1,3)
		Fo(j,1,3)
			Fo(k,1,3)
				z.num[i][j]=(z.num[i][j]+x.num[i][k]*y.num[k][j]%mod)%mod;
	return z;
}

Mat E;
Mat qpow(Mat x , LL y) {
	if(!y) return E;
	if(y==1) return x;
	Mat z=qpow(x,y>>1);
	if(y&1)
		return z*z*x;
	return z*z;
}

int main() {
	A=read(); B=read(); C=read(); D=read(); cin>>n; mod=read();
	E.E(); K.K(A,B); P.P(D-C,C,D); ans.E();
	len = n.length();
	Fo(i,0,len-1)
		num[i+1]=n[i]-'0'; 
	Ro(i,len,1) {
		if(i==len) {
			LL top=i;
			while(num[top]==0) {
				top--;
				flag = 1;
			}
			if(!flag) {
				ans=qpow(K,num[i]-1);
				K=qpow(K,10);			
			} else {
				num[top]--;
				Fo(j,top+1,len)
					num[j]=9;
				ans = ans * qpow(K,num[i]);
				K = qpow(K,10);					
			}
			continue;
		}
		ans = ans * qpow(K,num[i]);
		K = qpow(K,10);			
	}
	ans=ans*P;
	printf("%lld",ans.fib()%mod);
	return 0;
}

好了,这篇blog会一直更新,遇到新的类型就会更新上去,希望能对你对我有所帮助

内容概要:本文介绍了ENVI Deep Learning V1.0的操作教程,重点讲解了如何利用ENVI软件进行深度学习模型的训练与应用,以实现遥感图像中特定目标(如集装箱)的自动提取。教程涵盖了从数据准备、标签图像创建、模型初始化与训练,到执行分类及结果优化的完整流程,并介绍了精度评价与通过ENVI Modeler实现一键化建模的方法。系统基于TensorFlow框架,采用ENVINet5(U-Net变体)架构,支持通过点、线、面ROI或分类图生成标签数据,适用于多/高光谱影像的单一类别特征提取。; 适合人群:具备遥感图像处理基础,熟悉ENVI软件操作,从事地理信息、测绘、环境监测等相关领域的技术人员或研究人员,尤其是希望将深度学习技术应用于遥感目标识别的初学者与实践者。; 使用场景及目标:①在遥感影像中自动识别和提取特定地物目标(如车辆、建筑、道路、集装箱等);②掌握ENVI环境下深度学习模型的训练流程与关键参数设置(如Patch Size、Epochs、Class Weight等);③通过模型调优与结果反馈提升分类精度,实现高效自动化信息提取。; 阅读建议:建议结合实际遥感项目边学边练,重点关注标签数据制作、模型参数配置与结果后处理环节,充分利用ENVI Modeler进行自动化建模与参数优化,同时注意软硬件环境(特别是NVIDIA GPU)的配置要求以保障训练效率。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cls1277

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值