A/B
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 6867 Accepted Submission(s): 5457
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)。
Output
对应每组数据输出(A/B)%9973。
Sample Input
2 1000 53 87 123456789
Sample Output
7922 6060
Author
xhd
Source
HDU 2007-1 Programming Contest
问题链接:HDU1576 A/B
问题简述:参见上文。
问题分析:
这个问题有两种解法,一是用扩展欧几里得算法,二是用试探法。似乎后一种方法更快。
解法一:可以用解整数的不定方程来解决,即使用扩展欧几里德算法。
根据题意,输入的n=A%9973(没有输入A),A%B=0(A必能被B整除),B与9973互素(GCD(B,9973)=1)。
解题过程首先是建立方程,然后才能编写程序。
设x=(A/B)%9973(x是最终想计算的值),则9973k+x=A/B(k为整数),得A=9973Bk+xB。
因为n=A%9973与A=9973Bk+xB,所以xB%9973=n,得xB=n+9973y。
故:(x/n)B+(-y/n)9973=1=GCD(B,9973),该方程有解。
要求x和y,先求X=x/n和Y=-y/n,即先解方程BX+9973Y=1。
最后,x=X*n。
需要注意的是,求得的x有可能是负值,需要进行调整。
不过,这个计算方法好像比较花时间。
解法二:试探法
根据题意,输入的n=A%9973(没有输入A),A%B=0(A必能被B整除),B与9973互素(GCD(B,9973)=1)。
解题过程首先是建立方程,然后才能编写程序。
设x=(A/B)%9973(x是最终想计算的值,满足0<=x<=9972),则9973k+x=A/B(k为整数),得A=9973Bk+xB。
因为n=A%9973与A=9973Bk+xB,所以xB%9973=n,得xB=n+9973y,亦得xB-n=9973y。
故:(xB-n)%9973=0
对于上式,只需要用试探法就可以求得x。这样,程序运行速度相当快。
需要主意的是,变量类型为long时没有AC,改为long long就AC了,有点奇怪。也许评价系统所用编译版本的long类型不是64位的,才有这种情况。
扩展欧几里德算法解本问题的方法,时间上则比较慢。试探法有时也是高效率的。
程序说明:(略)。
AC的C语言程序如下(解法二):
#include <stdio.h>
int main(void)
{
int t, i, j;
long long n, b, a=9973;
scanf("%d", &t);
for(i=0; i<t; i++) {
scanf("%lld%lld", &n, &b);
for(j=0; j<a; j++)
if((j * b - n) % a == 0) {
printf("%d\n", j);
break;
}
}
return 0;
}
AC的C语言程序如下(解法一):
#include <stdio.h>
// 递推法实现扩展欧几里德算法
long exgcd(long a, long b, long *x, long *y)
{
long x0=1, y0=0, x1=0, y1=1;
long r, q;
*x=0;
*y=1;
r = a % b;
q = (a - r) / b;
while(r)
{
*x = x0 - q * x1;
*y = y0 - q * y1;
x0 = x1;
y0 = y1;
x1 = *x;
y1 = *y;
a = b;
b = r;
r = a % b;
q = (a - r) / b;
}
return b;
}
int main(void)
{
int t, i;
long n, b, a=9973, x, y;
scanf("%d", &t);
for(i=0; i<t; i++) {
scanf("%ld%ld", &n, &b);
exgcd(b, a, &x, &y);
x = (x + a) % a; // x有可能为负,需要调整
printf("%ld\n", x*n%a);
}
return 0;
}