题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1576
题目大意:见题目
解题思路:开始的时候,看到求(A/B)%9973感觉像是直接利用同余公式即可解决,回顾一下同余公式:
(a+b)mod n = ((a mod n)+(b mod n))mod n
(a-b)mod n = ((a mod n)-(b mod n) + n) mod n
ab mod n = (a mod n)(b mod n) mod n
于是我就想,是不是可以利用其中的乘法公式进行计算呢,过程如下:
(A/B)%9973
=(A*(1/B))%9973 也就是把A/B看成是A和1/B的乘积
=((A%9973)*(1/B%9973))%9973
=(n*(1/B%9973))%9973 因为题目中给出n=A%9973
=(n/B)%9973 题目中限制1 <= B <= 10^9,因此1/B一定<9973,即1/B%9973==1/B
然后我就利用推出的这个公式进行计算,发现结果都是错的…………………………其实不难理解,公式化简到最后其实又变成了某两个数做除法再求模,但同余公式中明显没有针对除法的公式,因此这道题又一次告诉我们:没有针对除法的同余公式……………………切记切记
然后发现题目中给出了一个条件:gcd(B,9973) = 1,于是想到可以构造一个关于B和9973的等式,这样就可以利用扩展欧几里得算法解决了,推导如下:
设(A/B)%9973=k,所以A/B = 9973x+k
A = 9973Bx+kB
又因为A%9973=n
所以 (9973Bx+kB)%9973=n
所以kB%9973=n
kB = 9973y+n
kB-9973y=n
等式两边同时除以n可得:
B*k/n - 9973y/n = gcd(B,9973)=1
然后利用扩展欧几里得算法即可得到k/n的值,将其乘n可得k,为使结果>0则(k%9973+9973)%9973
AC代码:
#include <iostream>
using namespace std;
#define MOD 9973
void extend_gcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x=1;
y=0;
return ;
}
else
{
extend_gcd(b,a%b,y,x);
y-=x*(a/b);
}
}
int main()
{
int x,y;
int t;
int n,b;
cin>>t;
while(t--)
{
cin>>n>>b;
extend_gcd(b,MOD,x,y);
x = (x%MOD+MOD)%MOD;
cout<<(x*n)%MOD<<endl;
}
return 0;
}