HDU1576 A/B【扩展欧几里得算法+试探法】

 

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;
}

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值