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;
}

 

posted @ 2016-08-24 15:32  樱花庄的龙之介大人  阅读(206)  评论(0编辑  收藏  举报