A/B
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3869 Accepted Submission(s): 2967
Problem Description
要求(A/B)%9973,但由于A很大,我们只给出n(n=A%9973)(我们给定的A必能被B整除,且gcd(B,9973) = 1)。
Input
数据的第一行是一个T,表示有T组数据。
每组数据有两个数n(0 <= n < 9973)和B(1 <= B <= 10^9)。
每组数据有两个数n(0 <= n < 9973)和B(1 <= B <= 10^9)。
Output
对应每组数据输出(A/B)%9973。
Sample Input
2 1000 53 87 123456789
Sample Output
7922 6060
n = A - [A / 9973] * 9973;A/B = x --> A= Bx;带入得Bx - [A / 9973] * 9973 --> Bx - 9973y = GCD(B, 9973) = 1;然后利用扩展欧几里得求解。、
1. 扩展欧几里得算法主要是求 a * x + b * y = GCD(a ,b)中的x,y的值
证明:
求解 x,y的方法的理解
设 a>b。
1,显然当 b=0,gcd(a,b)=a。此时 x=1,y=0;
2,a>b>0 时
设 ax1+ by1=gcd(a,b);
bx2+ (a mod b)y2=gcd(b,a mod b);
根据朴素的欧几里德原理有 gcd(a,b) = gcd(b,a modb);
则: ax1+ by1=bx2+ (a mod b)y2;
即: ax1+ by1=bx2+ (a - [a / b] * b)y2 = ay2 + bx2- [a / b] * by2;
也就是 ax1+ by1 == ay2+b(x2- [a / b] *y2);
根据恒等定理得:x1=y2; y1=x2- [a / b] *y2;
这样我们就得到了求解 x1,y1 的方法:x1,y1 的值基于 x2,y2.
上面的思想是以递归定义的,因为 gcd 不断的递归求解一定会有个时候 b=0,所以递归可以结束。
代码:
#include<iostream>
#include<cstdio>
#include<map>
#include<math.h>
#include<cstring>
#include<algorithm>
using namespace std;
/*扩展欧几里得,a*x+b*y=1
欧几里得算法也称作辗转相除法,此为欧几里得算法的扩展
*/
int ext_euclid(int a,int b,int &x, int &y)
{
int t,d;
if (b==0)
{
x=1;
y=0;
return a;
}
d = ext_euclid( b, a % b, x, y);//一直递归,直到a % b为0为止,然后记录 a 的值是x,y用公式推出
//下面是由其中一组解推出下一组的值。巧妙、
t = x;
x = y;
y = t - a / b * y;//推理得出公式
return d;
}
int main()
{
int t,n, b;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&b);
int x, y;
ext_euclid(b, 9973, x, y);
if(x < 0)
x = x + 9973;
x = (x * n) % 9973;
printf("%d\n",x);
}
return 0;
}