题解:
1.欧几里得算法:(辗转相除求gcd)
两个数都由几段两者的最小公倍数组成,
如果不停用大的/小的取余,当最后取余为0,说明小的那个数已经是只有一段了
就是最大公约数
------------------------
2. 取余的一种写法:
a%b = a-a/b*b //a/b*b可以把余数去掉
----------------------------------------------
3.扩展欧几里得算法:
用于求ax+by = gcd(a,b)的x,y的解
a*x1+b*y1 = gcd(a,b)
b*x2+(a%b)*y2 = gcd(b,a%b)
两个等式右边相等没问题吧
于是a*x1+b*y1 = b*x2+(a%b)*y2
然后用一下上面那个取余另一种写法,化简成
a*x1 + b*y1 = a*y2 + b(x2-[a/b]*y2)(用方括号,为了表示这是整除:example:【5/2】= 2)
对照得到:
x1 = y2
y1 = x2 - 【a/b】*y2
然后递归求解,到底后逐层向上,上一轮y就是这一轮x,y则需要根据上面结论计算一下
递归终点:if(b=0) gcd = a,x=1,y=0
代码:扩展欧几里得算法的代码
#define ll long long
void exgcd(ll a,ll b,ll& x,ll& y)
{
if (!b) {x=1;y=0;}
else {
exgcd(b,a%b,y,x);
y -= (a/b)*x;
}
}
4.对于本题,设x,y,令:
A = 9973*x + n
B = 输入的B
y = A/B =(9973*x+n)/B
------>整理一下得到:-9973x + b*y = n
因为gcd(-9973,b) = 1,所以对于 -9973*x+b*y=1,算出y之后乘以n就是A/B了
(PS:其实可以不乘直接求就行了)
代码:
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
void exgcd(ll a,ll b,ll& x,ll& y)
{
if (!b) {x=a;y=0;}
else {
exgcd(b,a%b,y,x);
y -= (a/b)*x;
}
}
int main()
{
int t;
ll n,b;
scanf("%d",&t);
while (t--){
scanf("%lld %lld",&n,&b);
ll x,y;
exgcd(-9973,b,x,y);
//printf("x=%lld y=%lld\n",x,y);
printf("%lld\n",(y*n%9973+9973)%9973);
}
return 0;
}