3 条题解
-
0Guest LV 0
-
2
广义斐波那契数列 F[x]=F[x-1]+F[x-2] 可以写成 F[x]=a*F[1]+b*F[2] 的形式
写一个暴力程序算一下a和bint a=0,b=0; void F(int n){ if(n==1)a++; else if(n==2)b++; else F(n-1),F(n-2); }
F[3]=1*F[1]+1*F[2]
F[4]=1*F[1]+2*F[2]
F[5]=2*F[1]+3*F[2]
F[6]=3*F[1]+5*F[2]
发现a,b是正常斐波那契数列的相邻两项。问题就变成了拓展欧几里得解决不定方程的问题。
从第10项开始计算裴波那契数列直到能够求出方程的正整数解。
如果当前的数列的项大于了n此题无解,不过题目似乎所有数据都有解。
由于裴波那契数列是指数增加的,所以算法时间是 O(log^2(n)) 的。
即使数据达到 10^18 也可以秒出答案,没有精度影响。代码参考:
#include<cstdio> using namespace std; //暴力开 long long typedef int int_; #define int long long //拓展欧几里得计算 a*x+b*y==gcd(a,b) 的某一个解 void exgcd(int a,int b,int &d,int &x,int &y){ if(b==0){d=a;x=1;y=0;} else{exgcd(b,a%b,d,y,x);y-=x*(a/b);} } //解不定方程 a*x+b*y==c 求出对x的最小非负整数解 //无解返回 -1 int solve(int a,int b,int c){ int d,x,y; exgcd(a,b,d,x,y); if(c%d)return -1; x*=(c/d);b/=d; return (x%b+b)%b; } int feb[1005]; int_ main(){ int N;scanf("%lld",&N); //递推求出到N的斐波那契数列 feb[0]=0;feb[1]=1; for(int k=2;;k++){ feb[k]=feb[k-1]+feb[k-2]; if(feb[k]>N)break; } //从第10项开始枚举求解 for(int k=10;feb[k]<=N;k++){ int x=solve(feb[k-1],feb[k],N); if(x!=-1){ int y=(N-feb[k-1]*x)/feb[k]; if(y>=0){ int ans=feb[k]*x+feb[k+1]*y; printf("%lld\n",ans); break; } } } return 0; }
-
1
官方题解
作为我出的题目呢,数据保证了不超过30000,因此可以使用广义斐波拉契的发展趋势来做。
为什么数据超过30000不能做了呢?因为计算机精度有限,否则是可以照样做下去的。
几乎所有的广义斐波拉契数列(全为正整数)两项之商会无限趋于(根号5+1)/2,这也是黄金比例。
因此可以用这个方法来做,当然黄金比例的值要取大一点。
时间复杂度O(1)
当然因为数据不大,大家也可以用楼上ZKX的方法做,更暴力,更准确。#include<algorithm> #include<iostream> #include<iomanip> #include<cstring> #include<cstdlib> #include<vector> #include<cstdio> #include<cmath> #include<queue> using namespace std; inline const long long Get_Int() { long long num=0,bj=1; char x=getchar(); while(x<'0'||x>'9') { if(x=='-')bj=-1; x=getchar(); } while(x>='0'&&x<='9') { num=num*10+x-'0'; x=getchar(); } return num*bj; } const long double tmp=(1+sqrt(5))/2; long long n; int main() { n=Get_Int(); printf("%lld\n",(long long)(tmp*n+0.5)); return 0; }
-
0
其实这道题啊!哼!这道题啊!不是很简单吗?
观察题目我们不妨可以发现题目只有两重限制即:
1.数据保证输入的数列中的数位于数列的第10项之后。
2.数列中的数只可能是正整数。
所以啊我们不妨搜一下,但注意到搜索范围过大后无法快速出答案,
算了加剪枝把!
Tips:#include<bits/stdc++.h>
#include<ctime>
using namespace std;
int m,Rec;bool vst[30005],bj=1;
inline int Get()
{
int num=0,bj=1;char x=getchar();
while(!isdigit(x))
{
if(x=='-')bj=-1;
x=getchar();
}
while(isdigit(x))
{
num=num*10+x-'0';
x=getchar();
}
return num*bj;
}
inline bool OK(int R)
{
int ans=0,Last=R,now=m,cnt;
while(true)
{
if(ans>=10&&!bj)return true;
if(ans>10&&bj==1)return true;
if(ans>=11&&bj==2)return true;
cnt=now;if(cnt<=0)return false;
now=Last-now;if(now<=0)return false;
Last=cnt;if(Last<=0)return false;
if(now>=Last)return false;
ans++;
}
}
int main()
{
srand((unsigned)time(NULL));bj=0;if(m>7500)bj=1;if(m>15000)bj=2;
m=Get();Rec=rand()*17317%(2*m/5)+8*m/5;vst[Rec]=true;
while(!OK(Rec))
{
Rec=rand()*17317%(2*m/5)+8*m/5;
if(vst[Rec])continue;
vst[Rec]=true;
}
printf("%d",Rec);
return 0;
}
- 1