题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1576
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 7264 Accepted Submission(s): 5774
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
题意:给出A%9973和B的值,求(A/B)%9973。
解析:(A / B) % p = (A * inv(B) ) % p = (A % p * inv(B) % p) % p,其中p为模数9973, inv(B)为B关于模p的逆元。
同余式:
如果两个正整数a和b之差能被n整除,那么我们就说a和b对模n同余,记作:a≡b (mod n)。
a≡b(mod n)等价于a与b分别用n去除,余数相同。
a≡b(mod n)等价于a与b分别用n去除,余数相同。
乘法逆元:
如果ax≡1 (mod p),且gcd(a,p)=1(a与p互质,此为一个数有逆元的充要条件,此时逆元唯一存在),则称a关于模p的乘法逆元为x。
逆元的含义:模n意义下,1个数a如果有逆元x,那么除以a相当于乘以x。
求解逆元的方法:
1. 扩展欧几里得算法:
已知整数a、b,扩展欧几里得算法可以在求得a、b的最大公约数的同时,能找到整数x、y(其中一个很可能是负数),使它们满足贝祖等式ax + by = gcd(a, b)。
当a关于模b的逆元存在,有gcd(a, b) == 1,即扩展欧几里得算法可求得x, y满足ax + by = 1, 两边同时余b,
ax % b + by % b = 1 % b
ax % b = 1 % b
ax ≡ 1(mod b)
所以x是a的模b乘法逆元,同理y是b的模a乘法逆元。
算法时间复杂度:O(logn)
模板代码:
1 int ex_gcd(int a, int b, int &x, int &y) { // 函数返回gcd(a, b) 2 if (b == 0) { 3 x = 1, y = 0; 4 return a; 5 } 6 int r = ex_gcd(b, a % b, y, x); 7 y -= (a / b) * x; 8 return r; 9 } 10 11 int main() { 12 int a, b, x, y; 13 cin >> a >> b; // 求a关于模b的逆元 14 cout << (ex_gcd(a, b, x, y) == 1 ? (x % b + b) % b : -1) << endl; // -1表示逆元不存在 15 16 return 0; 17 }
2. 费马小定理:
内容:假如a是一个整数,p是一个质数,那么ap - a是p的倍数,可以表示为
ap ≡ a (mod p)
如果a不是p的倍数(即gcd(a, p) == 1),这个定理也可以写成
ap-1 ≡ 1 (mod p)
变形得a * ap-2 ≡ 1 (mod p),所以a关于模p的逆元x = ap-2 (mod p),用快速幂模可快速求之。
算法时间复杂度:O(logn)
模板代码:
1 LL pow_mod(LL a, LL b, LL p) { //a的b次方取模p 2 LL ret = 1; 3 while (b) { 4 if(b & 1) ret = (ret * a) % p; 5 a = (a * a) % p; 6 b >>= 1; 7 } 8 return ret; 9 } 10 LL Fermat(LL a, LL p) { //费马小定理求a关于b的逆元 11 return pow_mod(a, p-2, p); 12 }