P7318 「PMOI-4」人赢の梦

这个得先了解用矩阵求斐波那契数列:

详细点这里
很多方法,最简单的就是找循环节(前面写挂好几次 悲),还有就是矩阵。
对于题目,我们发现有下列数列:

\[n,m,nm,nm^2,n^2m^3,n^3m^5,n^5m^8,n^8m^{13} \]

从第四项开始,\(n\),\(m\)的次数都是有规律的:斐波那契数列。
快速幂矩阵乘所求的斐波那契数列为:

\[1,2,3,5,8,13,21,34,55,89 \]

但是实现好像出了点问题:

#include <bits/stdc++.h>
#define ll long long
#define re register
using namespace std;
const int N=800, INF=0x3f3f3f3f,mod=100000;
ll n,m,k;
ll ans[3][3];
ll a[3][3];
void f1(){//ans=a*ans
	ll A[3][3]={0};
	for(int i=1;i<=2;i++)
		for(int j=1;j<=2;j++)
			for(int k=1;k<=2;k++)
				A[i][j]+=a[i][k]*ans[k][j]%mod;
	for(int i=1;i<=2;i++)
		for(int j=1;j<=2;j++)
			ans[i][j]=A[i][j];
}
void f2(){//a=a*a
	ll A[3][3]={0};
	for(int i=1;i<=2;i++)
		for(int j=1;j<=2;j++)
			for(int k=1;k<=2;k++)
				A[i][j]+=a[i][k]*a[k][j]%mod;
	for(int i=1;i<=2;i++)
		for(int j=1;j<=2;j++)
			a[i][j]=A[i][j];
}
ll FIB(ll  x){
	if(x<=2)return 1;
	for(int i=1;i<=2;i++)ans[i][i]=1;
	a[1][1]=1;a[1][2]=1;a[2][1]=1;a[2][2]=0;
	x-=2;
	while(x>0){
		if(x&1)f1();
		f2();
		x>>=1;
	}
	ll r=ans[1][1]+ans[1][2];
	return r%mod;
}
ll QP(ll x,ll y){
	ll base=x,ans=1;
	while(y>0){
		if(y&1){
			ans*=base;
			ans%=10;
		}
		base*=base;
		base%=10;
		y>>=1;
	}
	return ans;
}
int main(){
	cin>>n>>m>>k;
	if(k==1){
		cout<<n<<endl;
		return 0;
	}
	if(k==2){
		cout<<m<<endl;
		return 0;
	}
	ll p,q;
	p=FIB(k-2);
	q=FIB(k-1);
	cout<<QP(n,p)*QP(m,q)%10<<endl;
	return 0;
}

WA了四个。不知道为什么,基本实现应该是没有问题的。
UNKNOWN!!!
而且如果\(mod=1\)也就是不模的话,WA了七个。模多了到\(1e9\)也没用。

发现问题,上面这个代码\(f1\)中,应该是\(ans\)矩阵乘以\(a\)矩阵。先前几道题因为构造的矩阵正乘反乘都一样,所以没有区别。而且,每个矩阵运算的取模似乎也有问题,下次不能图省事。并且,最大的一个问题是求FIB里,最后返回值应该是\(a[1][1]\%10\)

ans*=base相当于ans=ans*base。所以一目了然。

#include <bits/stdc++.h>
#define ll long long
#define re register
using namespace std;
const int N=800, INF=0x3f3f3f3f,mod=10000;
ll n,m,k;
ll ans[3][3];
ll a[3][3];
void f1(){//ans=ans*a
	ll A[3][3]={0};
	for(int i=1;i<=2;i++)
		for(int j=1;j<=2;j++)
			for(int k=1;k<=2;k++){
				A[i][j]+=ans[i][k]*a[k][j];
				A[i][j]%=mod;
			}
	for(int i=1;i<=2;i++)
		for(int j=1;j<=2;j++)
			ans[i][j]=A[i][j]%mod;
}
void f2(){//a=a*a
	ll A[3][3]={0};
	for(int i=1;i<=2;i++)
		for(int j=1;j<=2;j++)
			for(int k=1;k<=2;k++){
				A[i][j]+=a[i][k]*a[k][j];
				A[i][j]%=mod;
			}
	for(int i=1;i<=2;i++)
		for(int j=1;j<=2;j++)
			a[i][j]=A[i][j]%mod;
}
ll FIB(ll  x){
	if(x<=2)return 1;
	for(int i=1;i<=2;i++)ans[1][i]=1;
	a[1][1]=1;a[1][2]=1;a[2][1]=1;a[2][2]=0;
	x-=2;
	while(x>0){
		if(x&1)f1();
		f2();
		x>>=1;
	}
	ll r=ans[1][1]%mod;
	return r;
}
ll QP(ll x,ll y){
	ll base=x,ans=1;
	while(y>0){
		if(y&1){
			ans*=base;
			ans%=10;
		}
		base*=base;
		base%=10;
		y>>=1;
	}
	return ans;
}
int main(){
	cin>>n>>m>>k;
	if(k==1){
		cout<<n<<endl;
		return 0;
	}
	if(k==2){
		cout<<m<<endl;
		return 0;
	}
	ll p,q;
	p=FIB(k-2);
	q=FIB(k-1);
	cout<<QP(n,p)*QP(m,q)%10<<endl;
	return 0;
}

这题如果用矩阵做,就两点注意:一个是注意取模,避免炸了。第二个(对我来说)看清顺序(悲
而且还得学一下用矩阵求斐波那契数列(NEW)。

本题求斐波那契数列:

\[\begin{bmatrix}1\quad 1\end{bmatrix}·\begin{bmatrix}1&1\\1&0\end{bmatrix}^{i-2} \]

posted @ 2023-07-12 22:26  LsmQwQ  阅读(45)  评论(0)    收藏  举报