GDUT 2020寒假训练 数论 C
原题链接
题目
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。
样例
input
2
1000 53
87 123456789
output
7922
6060
思路
扩展欧几里得求乘法逆元
对于
,设
满足
那么x也就是b在mod p意义下的倒数,也就是我们要找的b的逆元,即
那么将这个同余方程展开可得
即
这个形式就和扩展欧几里得的形式相似了,那么注意到p为质数也就是bp互质即
那么现在这个形式就和拓展欧几里得的表达式一样了,利用拓展欧几里得计算exgcd(b,p,x,y,)最后的x就是b的逆元
代码
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
long long exgcd(long long a,long long b,long long &x,long long &y)
{
if(b==0)
{
x=1,y=0;
return a;
}
long long d=exgcd(b,a%b,x,y);
long long temp=x;
x=y;
y=temp-(a/b)*y;
return d;
}
int main()
{
int T;
cin>>T;
while(T--)
{
long long n,b,x,y;
cin>>n>>b;
exgcd(b,9973,x,y);//x为b的逆元
x+=9973;
x%=9973;
cout<<(n*x)%9973<<endl;
}
return 0;
}
快速幂求乘法逆元
由费马小定理
假如a是一个整数,p是一个质数,那么 是p的倍数,表示为
将表达式转换一下可以得到
即
也就是
是
的逆元,那么就可以通过快速幂求a的逆元了。
代码
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
long long power(long long a,long long b,long long mod)
{
long long ans=1%mod;
for(;b;b>>=1)
{
if(b&1)
{
ans=ans*a%mod;
}
a=a*a%mod;
}
return ans;
}
int main()
{
int T;
cin>>T;
while(T--)
{
long long n,b,x;
cin>>n>>b;
x=power(b,9973-2,9973);
//x+=9973;
//x%=9973;
cout<<(n*x)%9973<<endl;
}
return 0;
}