csu1941(exgcd)

来源:互联网 发布:c语言dll库详解 编辑:程序博客网 时间:2024/06/04 00:35

题目链接:点击打开链接

// csu 1941// 大概题意:求一个a* f[i]+b* f[i- 1]= g的解,b为第一关键字最小,a为第二关键字#include <iostream>#include <algorithm>#include <fstream>#include <sstream>#include <iomanip>#include <cstdio>#include <vector>#include <cstring>#include <cmath>#include <queue>#include <stack>#include <set>#include <map>#define ll long longusing 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;}



原创粉丝点击