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} \]