interesting Integers(数学暴力||数论扩展欧几里得)
题意:给你一个数 n ,n 是以 a b 为第一项和第二项数列的某一项,求一个满足的 a b ,要求b尽可能的小(a<=b).
f[1] = a,f[2] = b,f[3]=a+b,f[4]=a+2*b,f[5] = 2*a+3*b....
我们发现新的数组的第 k 项为 原来的斐波拉契数列的第 k-1项 乘b 加上第 k-2 乘a,所以打个表,反向枚举 b 即可.耗时:500ms+
#include<stdio.h> #include<iostream> #include<string.h> #include <stdlib.h> #include<math.h> #include<algorithm> using namespace std; typedef long long LL; int f[50]; int main() { f[1] = f[2] = 1; for(int i=3;i<=45;i++){ f[i] = f[i-1] + f[i-2]; } int tcase; scanf("%d",&tcase); while(tcase--) { int num; scanf("%d",&num); int a=999999999,b=999999999,c=999999999; for(int i=45;i>=3;i--){ for(int j=1;j<=b;j++){ int temp = num-f[i-1]*j; if(temp<=0) break; if(temp%f[i-2]==0){ temp = temp/f[i-2]; if(temp>j) continue; b = j; a = temp; } } } printf("%d %d\n",a,b); } return 0; }
数论扩展欧几里得:
对每一个式子进行扩展欧几里得.
耗时 15ms
#include<stdio.h> #include<iostream> #include<string.h> #include <stdlib.h> #include<math.h> #include<algorithm> using namespace std; typedef long long LL; LL f[50]; LL extend_gcd(LL a,LL b,LL &x,LL &y) { if(!b) { x=1,y = 0; return a; } else { LL x1,y1; LL d = extend_gcd(b,a%b,x1,y1); x = y1; y = x1 - a/b*y1; return d; } } int main() { f[1] = f[2] = 1; for(int i=3; i<=45; i++) { f[i] = f[i-1] + f[i-2]; } int tcase; scanf("%d",&tcase); while(tcase--) { LL num; scanf("%I64d",&num); LL a=999999999,b=999999999; for(int i=45; i>=3; i--) { LL x,y; LL d = extend_gcd(f[i-2],f[i-1],x,y); if(num%d)continue; LL temp_n = num/d; LL temp_a = f[i-2]/d; LL temp_b = f[i-1]/d; x = x*temp_n; x = (x%temp_b+temp_b)%temp_b; ///最小的x y = (num-x*f[i-2])/f[i-1]; ///最小的 x时候的y while(y<=b&&x<=y) { if((y<b||(y==b&&x<a))&&(x>0)) { b = y; a = x; } y-=temp_a; x+=temp_b; ///这里进行 加减 可以得到所有通项. } } printf("%I64d %I64d\n",a,b); } return 0; }