问题及代码:
运行结果:
Problem E A/B-(A/B)%9973
Time Limit : 1000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 3 Accepted Submission(s) : 3
Font: Times New Roman | Verdana | Georgia
Font Size: ← →
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
/*
*Copyright (c)2015,烟台大学计算机与控制工程学院
*All rights reserved.
*文件名称:HDU.cpp
*作 者:单昕昕
*完成日期:2015年3月2日
*版 本 号:v1.0
*/
//AC代码1
#include<iostream>
using namespace std;
int exGcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x=1;
y=0;
return a;
}
int r=exGcd(b,a%b,x,y);
int t=x;
x=y;
y=t-a/b*y;
return r;
}
int main()
{
int b,x,y,t,n;
cin>>t;
while(t--)
{
cin>>n>>b;
exGcd(b,9973,x,y);
x=x*n;
x=(x%9973+9973)%9973;
cout<<x<<endl;
}
}
//AC代码2
#include<iostream>
#include<cmath>
using namespace std;
int exGcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x=1;
y=0;
return a;
}
int r=exGcd(b,a%b,x,y);
int t=x;
x=y;
y=t-a/b*y;
return r;
}
int main()
{
int b,x,y,t,n;
cin>>t;
while(t--)
{
cin>>n>>b;
exGcd(b,9973,x,y);
x*=n;
x%=9973;
x+=9973;
cout<<x<<endl;
}
}
运行结果:
拓展欧几里得算法。
乘法逆元。
学习心得:
研究了一个多小时才看懂拓展欧几里得算法怎么用。
n = A%9973, 设A / 9973 = y;
A / B = x 得 A = B * x;
有: B*x - 9973 * y = n;
由n=A%9973,得A=n+y*9973,即n=A-9973y;
又由扩展欧几里得公式得:ax+by=gcd(a,b);
由A必能被B整除,即A%B==0,所以设A/B=X,A=B*X,得n=Bx-9973y。
引自yanghuaqings:
这道题应该用拓展欧几里德算法,总的思路是 (N = 9973):(A/B)%N = ( (A%N) * (1/B)%N)%N
因为 gcd(B,N) = 1,所以 原式= (n * (gcd(B,N)/B)%N)%N
又因为根据拓展欧几里德算法可以得到一组x,y,使得gcd(B,N) = B*x + N*y,代入上式就可以得到
(n * (x + N*y/B)%N)%N= ((n%N) * (x + N*y/B)%N)%N= (n*(x+N*y/B))%N
因为y < B,所以y/B = 0所以原式G= (n*x)%N
又因为x可能为负,所以只要G = (G%N+N)%N,就可以化成正的了。