csu1941(exgcd)

题目链接:点击打开链接

// csu 1941
// 大概题意:求一个a* f[i]+b* f[i- 1]= g的解,b为第一关键字最小,a为第二关键字


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define ll long long

using namespace std;

ll f[50];

ll gcd(ll a, ll b)
{
    if(!b) return a; else return gcd(b, a% b);
}

void exgcd(ll a, ll b, ll &d, ll &x, ll &y)
{
    if(!b) { d= a; x= 1; y= 0; }
    else { exgcd(b, a% b, d, y, x); y-= x* (a/ b); }
}

int main()
{
    f[1]= 1; f[2]= 1;
    for(int i= 3; i<= 50; i++) f[i]= f[i- 1]+ f[i- 2];
    int T; cin >> T;
    while(T--)
    {
        ll g, ansa= 1000000007, ansb= 1000000007, anst; scanf("%lld", &g);
        for(int i= 1; i<= 50; i++)
            if(g% gcd(f[i], f[i+ 1])== 0)                   // 其实由于斐波那契相邻两项互质(没有证明)可以省去这一步,并且之后的d都省略
            {
                ll x, y, d, a= f[i], b= f[i+ 1];
                exgcd(a, b, d, x, y);
                x*= g/ d; y*= g/ d;                        //调用后,(x,y)为最靠近零的整数解
                if(x<= 0)
                {
                    ll k= b/ d;
                    ll xx= (x% k+ k)% k;
                    ll t= (xx- x)/ k;
                    x= xx; y-= t* a/ d;
                }
                /*
                ll t= abs(y- x)/(a/ d+ b/ d);
                if(x< y) { x+= b* t/ d; y-= a* t/ d; }    //这几行很丑!完全抄的非正解
                else                                      // y= y0- a/ d* t x= x0+ b/ d* t;
                {                                         // y> x 然后推出t的范围.......至于这样做为什么对完全不解;
                    if(abs(y- x)% (a/ d+ b/ d)) t++;      //应该是因为exgcd本身的性质吧!不过好像懂一点点了,
                    x-= b* t/ d; y+= a* t/ d;
                }
                */

                ll t= (y- x)/(a/ d+ b/ d);                 //这是我自己改的,貌似科学了点,但是还是wa
                ll x0= x, y0= y;                           //就是说abs(y0- x0)% (a/ d+ b/ d)不是整除的时候,c++是向0取整,当t为负时所以这时要t--
                x=x0+ b* t/ d; y=y0- a* t/ d;              //貌似对了!嘎嘎嘎嘎嘎嘎!!!!!
                if((y0< x0) && abs(y0- x0)% (a/ d+ b/ d)) { t--; x=x0+ b* t/ d; y=y0- a* t/ d;}
                if((x> 0) && (y>= x) && ((y< ansb) || (y== ansb && x< ansa)))
                {
                    ansb= y; ansa= x; anst= a* t;
                }
            }
        printf("%lld %lld\n", ansa, ansb);
    }
    return 0;
}



你可能感兴趣的:(csu,exgcd)