序号 | 取模概念下的加减乘除 | 正确性 |
---|---|---|
1 | ( a + b ) (a+b) (a+b) % p = ( a p=(a p=(a % p + b p+b p+b % p ) p) p) % p p p | 正确 |
2 | ( a − b ) (a-b) (a−b) % p = ( a p=(a p=(a % p − b p-b p−b % p ) p) p) % p p p | 正确 |
3 | ( a ∗ b ) (a*b) (a∗b) % p = [ ( a p=[(a p=[(a % p ) ∗ ( b p)*(b p)∗(b % p ) ] p)] p)] % p p p | 正确 |
4 | ( a / b ) (a / b) (a/b) % p = [ ( a p=[(a p=[(a % p ) / ( b p) / (b p)/(b % p ) ] p)] p)] % p p p | 错误 |
快速幂(Fast Power)是一种高效计算乘方的方法,主要用于计算大整数的大幂次方。其基本思想是利用分治思想和乘方的对数规律,将运算复杂度从 O ( n ) O(n) O(n) 降低到 O ( log n ) O(\log n) O(logn)。
a k = a 2 x 1 ∗ a 2 x 2 ∗ a 2 x 3 ∗ . . . = a 2 x 1 + 2 x 2 + 2 x 3 + . . . a^k = a^{2^{x_1}} * a^{2^{x_2}} * a^{2^{x_3}} * ... = a^{2^{x_1} + 2^{x_2} + 2^{x_3} + ...} ak=a2x1∗a2x2∗a2x3∗...=a2x1+2x2+2x3+...
题目描述:
给定 n n n 组 a i , b i , p i a_i,b_i,p_i ai,bi,pi,对于每组数据,求出 a i b i m o d p i a_i^{b_i} \mod p_i aibimodpi 的值。
输入格式:
第一行包含整数 n n n。
接下来 n n n 行,每行包含三个整数 a i , b i , p i a_i,b_i,p_i ai,bi,pi。
输出格式:
对于每组数据,输出一个结果,表示 a i b i m o d p i a_i^{b_i} \mod p_i aibimodpi 的值。
每个结果占一行。
数据范围:
1 ≤ n ≤ 100000 , 1 ≤ a i , b i , p i ≤ 2 × 1 0 9 1≤n≤100000,1≤a_i,b_i,p_i≤2×10^9 1≤n≤100000,1≤ai,bi,pi≤2×109
输入样例:
2
3 2 5
4 3 9
输出样例:
4
1
模运算的性质: ( a ∗ b ) (a * b) (a∗b) % p = ( a p = (a p=(a % p ∗ b p * b p∗b % p ) p) p) % p p p
#define _CRT_NO_SECURE_WARNINGS
#include
using namespace std;
int qmi(int a, int b, int p)
{
long long res = 1 % p; // 防止 p=1 的情况
while (b)
{
if (b & 1) res = res * a % p;
a = a * (long long)a % p;
b >>= 1;
}
return res;
}
int main()
{
int n;
cin >> n;
while (n--)
{
int a, b, p;
cin >> a >> b >> p;
cout << qmi(a, b, p) << endl;
}
return 0;
}
题目描述:
( 64 64 64位整数乘法)求 a a a 乘 b b b 对 p p p 取模的值。
输入格式:
第一行输入整数 a a a,第二行输入整数 b b b,第三行输入整数 p p p。
输出格式:
输出一个整数,表示 a ∗ b m o d p a∗b \mod p a∗bmodp的值。
数据范围:
1 ≤ a , b , p ≤ 1 0 18 1≤a,b,p≤10^{18} 1≤a,b,p≤1018
输入样例:
3
4
5
输出样例:
2
思路:
二进制思想。如果直接计算 a × b a×b a×b 这会爆 long long
,所以采用 类似于快速幂的思想
把 b b b 作为二进制形式进行处理,然后如果某位上为 1 1 1 就加上它 a × 2 a×2 a×2 对应的次方,并且每次计算后取模就可以了。
例如: b = 11 = ( 1011 ) 2 = 23 + 21 + 20 b=11=(1011)_2=23+21+20 b=11=(1011)2=23+21+20,那么 a × b = a × ( 2 3 + 2 1 + 2 0 ) = 8 a + 2 a + a a×b=a×(2^3+2^1+2^0)=8a+2a+a a×b=a×(23+21+20)=8a+2a+a。
代码实现:
#define _CRT_NO_SECURE_WARNINGS
#include
using namespace std;
long long mul(int a, int b, int p)
{
long long res = 0;
while (b)
{
if (b & 1) res = (res + a) % p;
a = (a % p + a % p) % p;
b >>= 1;
}
return res;
}
int main()
{
long long a, b, p;
cin >> a >> b >> p;
cout << mul(a, b, p) << endl;
return 0;
}
若整数 b , m b,m b,m 互质,并且对于任意的整数 a a a,如果满足 b ∣ a b|a b∣a,则存在一个整数 x x x,使得 a b ≡ a × x ( m o d m ) \frac{a}{b} ≡ a × x (\mod m) ba≡a×x(modm),则称 x x x 为 b b b 的模 m m m 乘法逆元,记为 b − 1 ( m o d m ) b^{-1} (\mod m) b−1(modm)。
b b b 存在乘法逆元的充要条件是 b b b 与模数 m m m 互质。
同时可以写作为 b ∗ b − 1 ≡ 1 ( m o d m ) b*b^{-1} ≡ 1(\mod m) b∗b−1≡1(modm)
当模数 m m m 为质数时, b m − 2 b^{m-2} bm−2 即为 b b b 的乘法逆元。由欧拉定理 a φ ( m ) ≡ 1 ( m o d m ) a^{φ(m)} ≡1(\mod m) aφ(m)≡1(modm),当 m m m 为质数时, φ ( m ) = m − 1 φ(m) = m - 1 φ(m)=m−1,则可以配出 b ∗ b m − 2 ≡ 1 ( m o d m ) b*b^{m-2} ≡ 1(\mod m) b∗bm−2≡1(modm) 的表达式,即 b b b 的乘法逆元为 b m − 2 b^{m-2} bm−2 。
题目描述:
给定 n n n 组 a i , p i a_i,p_i ai,pi,其中 p i p_i pi 是质数,求 a i a_i ai 模 p i p_i pi 的乘法逆元,若逆元不存在则输出 impossible
。
输入格式:
第一行包含整数 n n n。
接下来 n n n 行,每行包含一个数组 a i , p i a_i,p_i ai,pi,数据保证 p i p_i pi 是质数。
输出格式:
输出共 n n n 行,每组数据输出一个结果,每个结果占一行。
若 a i a_i ai 模 p i p_i pi 的乘法逆元存在,则输出一个整数,表示逆元,否则输出 impossible
。
数据范围:
1 ≤ n ≤ 1 0 5 , 1 ≤ a i , p i ≤ 2 × 1 0 9 1≤n≤10^5,1≤a_i,p_i≤2×10^9 1≤n≤105,1≤ai,pi≤2×109
输入样例:
3
4 3
8 5
6 3
输出样例:
1
2
impossible
#define _CRT_NO_SECURE_WARNINGS
#include
using namespace std;
int qmi(int a, int b, int p)
{
int res = 1 % p;
while (b)
{
if (b & 1) res = res * a % p;
a = a * (long long)a % p;
b >>= 1;
}
return res;
}
int main()
{
int n;
cin >> n;
while (n--)
{
int a, p;
cin >> a >> p;
int res = qmi(a, p - 2, p);
if (res % p == 0) cout << "impossible" << endl;
else cout << res << endl;
}
return 0;
}