A/B HDU-1576 (乘法逆元and拓展欧几里得)
A/B HDU-1576
要求(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
题解:
需要知道(背过)的定理:逆元 (a/b) (mod N) = (a * x) (mod N)。 x表示b的逆元。并且 b*x ≡ 1 (mod N )。
题目让求A/B%9973 即A/B%9973=A*x%9973 x为B的逆元。故B*x≡1 (mod 9973)变形为B*x-9973*y=1 套用拓展欧几里得求x。又因为n=A%9973,即可以求出答案。(拓展欧几里得既可以求出a,b的最大公约数,又可以求出满足ax+by=gcd(a,b)的一组x,y的解)
1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<algorithm>
5 using namespace std;
6 int gcd(int a,int b,int &x,int &y)
7 {
8 if(b==0)
9 {
10 x=1;
11 y=0;
12 return a;
13 }
14 int q=gcd(b,a%b,y,x);
15 y-=a/b*x;
16 return q;
17 }
18 int main()
19 {
20 int n,b,x,y,t;
21 scanf("%d",&t);
22 while(t--)
23 {
24 scanf("%d%d",&n,&b);
25 gcd(b,9973,x,y);
26 x=x*n;
27 printf("%d\n",(x%9973+9973)%9973);
28 }
29 return 0;
30 }
用乘法逆元的解法:
根据费马小定理,对于素数n,任意不是n的倍数的b,都有: b^(N-1)=1(mod N)---->b*b^(N-2)=1(mod N)----->b的逆元为b^(N-2),
1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 typedef long long ll;
5 const int maxn=1e5+10;
6 #define mod 9973
7 using namespace std;
8 ll powmod(ll a,ll b)
9 {
10 ll ans=1;
11 while(b)
12 {
13 if(b&1)
14 ans=(ans*a)%mod;
15 a=(a*a)%mod;
16 b>>=1;
17 }
18 return ans%mod;
19 }
20 int t;
21 int n,b;
22 int main()
23 {
24 cin>>t;
25 while(t--)
26 {
27 scanf("%d%d",&n,&b);
28 b=b%mod;
29 printf("%lld\n",(n*powmod(b,mod-2)+mod)%mod);
30 }
31 return 0;
32 }