洛谷 P3938 斐波那契
题目分析
今天考试的第一题,我们要有梦想!根据所给的特殊性质和数据范围,我们照样可以拿70分的高分!
以下是70分程序
#include<cstdio>
#include<algorithm>
using namespace std;
#define re register
int m;
long long w[20][20];
long long f[10010];
inline int read(){
int x=0,w=1;char ch=0;
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='0') w=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch-48),ch=getchar();
return x*w;
}
int main(){
freopen("fibonacci.in ","r",stdin);
freopen("fibonacci.out","w",stdout);
scanf("%d",&m);
for(re int i=1;i<=15;i++)//打表
for(re int j=i;j<=15;j++){
if(i==j)w[i][j]=i;
else if(i==2&&(j==5||j==7||j==10||j==13||j==15))w[i][j]=w[j][i]=2;
else if(i==3&&(j==8||j==11))w[i][j]=w[j][i]=3;
else if(i==4&&j==12)w[i][j]=w[j][i]=4;
else if(i==5&&j==13)w[i][j]=w[j][i]=5;
else if(i==5&&(j==7||j==10||j==15))w[i][j]=w[j][i]=2;
else if(i==7&&(j==10||j==15||j==13))w[i][j]=w[j][i]=2;
else if(i==8&&j==11)w[i][j]=w[j][i]=3;
else if(i==10&&(j==15||j==13))w[i][j]=w[j][i]=2;
else if(i==13&&j==15)w[i][j]=w[j][i]=2;
else w[i][j]=w[j][i]=1;
}
f[1]=1;f[0]=1;
for(re int i=2;i<=60;i++)f[i]=f[i-1]+f[i-2];
while(m--){
long long a,b;
a=read();b=read();
if(abs(a-b)<=1){ if(a==b)printf("%lld\n",a); else printf("1\n"); continue; }
if(a<=15&&b<=15){ if(a>b)swap(a,b);printf("%lld\n",w[a][b]); continue; }
if(a==1||b==1){printf("1\n");continue;}
int p1=0,p2=0;
for(re int i=1;i<=60;i++){ if(a==f[i]) p1=i; if(b==f[i]) p2=i; }
if(p1%2==1&&p2%2==1)printf("%lld\n",min(a,b));
else if(p1%2==0&&p2%2==0)printf("%lld\n",min(a,b));
else printf("1\n");
}
return 0;
}
然后我们仔细分析题目,可以发现每个点与他的父亲节点的差值都是斐波那契数列中的一个数,于是我们再用倍增的思想,先把1到60的斐波那契的预处理出来,然后按照倍增做LCA的思想去做就可以了。
//注意开longlong
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int n;
long long f[65];
inline long long read(){
long long x=0,w=1;char ch=0;
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='0') w=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch-48),ch=getchar();
return x*w;
}
int main(){
n=read();
f[1]=1;f[2]=2;
for(register int i=3;i<=62;++i) f[i]=f[i-1]+f[i-2];
for(register int i=1;i<=n;++i) {
long long a=read(),b=read();
if(a==b){cout<<a<<endl;continue;}
for(register int i=60;i>=1;--i) {
if(a>f[i]) a-=f[i];
if(b>f[i]) b-=f[i];
if(a==b) {//相等的时候就可以输出了
cout<<a<<endl;break;
}
}
}
return 0;
}