扩展欧几里得 HDU 1576

题意;要求(A/B)%9973,但由于A很大,我们只给出n(n=A%9973)(我们给定的A必能被B整除,且gcd(B,9973) = 1)。

因为:A%9973=n;

所以:9973*y+n=A:

设:A/B=x;(可以整除)

所以:9973*y+n=B*x;

所以:B*x-9973*y=n; ①式

又因为:gcd(B,9973) = 1;

所以必存在 x1*B+9973*y1=1;②式

②式*n=①式

所以只要求出x1,就可以得到x,又因为x=a/b,只要在 mod 9973就是答案了。

现在给出扩展欧几里得:

对于gcd(a,b) = d,对(a, b)用欧几里德辗转相除会最终得到(d, 0)。此时对于把a =d, b = 0 代入a*x + b*y = d,显然x = 1,y可以为任意值。 我们可以用a = d, b = 0的情况逆推出来任何gcd(a, b) = d 满足a*x + b*y = d的解。如果x0,y0是b*x + (a%b)*y = d 的解,那么对于a*x + b*y = d的解呢?

b*x + (a%b)*y = d → b*x + (a - [a/b]*b)*y = d → a*y + b*(x - [a/b]*y) = d 所以a*x + b*y = d的解 x1 = y0,y1= x0 - [a/b]*y0;

我们可以地推出a*x+b*y=gcd(a,b),中的下,x和y.现在所有问题就解决了。

 

#include<stdio.h>
#include<cstring>
#include<iostream>
#define ll long long
using namespace std;
void ex_gcd(ll a,ll b,ll &x,ll &y)
{
  if(b==0)
  {
    x=1,y=0;
    return ;
  }
  ex_gcd(b,a%b,x,y);
  ll temp=x;
  x=y;
  y=temp-a/b*y;
  return ;
}
int main()
{
  ll t,a,b,n,x,y;
  cin>>t;
  while (t--)
  {
    cin>>n>>b;
    int ans;
    ex_gcd(b,9973,x,y);
    x=x*n;
    ans=(x%9973+9973)%9973;//(a + b) % p = (a % p + b % p) % p,所以(x%9973+9973)%9973=x%9973,若x是负数,x%9973会出错,所以化                                    成(x%9973+9973)%9973,先使x变正再 mod 9973
    cout<<ans<<endl;
  }
  return 0;

}


    cout<<ans<<endl;
  }
  return 0;

}

 

posted @ 2016-08-02 09:53  BaiMaSangBu  阅读(282)  评论(0编辑  收藏  举报