学数论的时候写过一篇关于扩展欧几里德求解模的逆元的博客,但是当时都不知道求逆元有什么用...(难过
http://blog.csdn.net/only_air/article/details/51033846
参考:
http://blog.csdn.net/cqlf__/article/details/7953039
http://blog.csdn.net/acdreamers/article/details/8220787
在计算 (a / b ) mod c 时,往往需要先计算 b mod c 的逆元 p(b 有逆元的条件是 gcd(b, c) == 1)
然后由 (a * p) mod c 得结果 ans,(这里 b 的逆元 p 满足 (b * p) mod c = 1)
先来简单证明一下:
(a / b) mod c = ans
(b * p) mod c = 1
==》 (a / b) * (b * p) mod c = ans
==》 (a * p) mod c = ans
接下来就需要知道根据 b 和 c,怎么计算逆元 p 了
①费马小定理
对于质数 p 和任意整数 a,有 a ^ p ≡ a (mod p)
将两边同时约去一个 a,则有 a ^ (p - 1) ≡ 1(mod p)
推导过程:
c 为素数,根据费马小定理
==》b ^ c ≡ b (mod c)
==》b ^ (c - 1) ≡ 1 (mod c)
==》b * (b ^ (c - 2)) ≡ 1 (mod c)
==》逆元 p = b ^ (c - 2) mod c
②扩展欧几里德算法
b * p mod c = 1 等价于 b * p = c * y + 1 即 b * p + c * (-y) = 1
根据扩展欧几里德算法,求出 p 和(-y)
p 应为正整数,即若 p 为负整数,需要将之化正整数,即与负数取模同理,将 p 加上 y,直至 p > 0为止,所得的数即为乘法逆元
③通用的求逆元方法
ans = (a / b) mod c = a mod (c * b) / b
证明如下
已知 b | a
(a / b) = k * c + ans
a = k * b * c + ans * b
a mod (b * c) = ans * b
a mod (b * c) / b = ans
51Nod 1256 乘法逆元
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <map>
#include <cmath>
#include <cctype>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
const ull mod = 1e9 + 7;
const int INF = 0x7fffffff;
int X, Y;
int Ext_Gcd(int a, int b);
int main()
{
#ifdef __AiR_H
freopen("in.txt", "r", stdin);
#endif // __AiR_H
int M, N;
scanf("%d%d", &M, &N);
Ext_Gcd(M, N);
while (X < 0) {
X += N;
}
printf("%d\n", X);
return 0;
}
int Ext_Gcd(int a, int b)
{
if (b == 0) {
X = 1;
Y = 0;
return a;
}
int gcd = Ext_Gcd(b, a%b);
int t = X;
X = Y;
Y = t - a/b * Y;
return gcd;
}
CodeForces_678D Iterated Linear Function
题意:
f(x) = Ax + B,g(0)(x) = x andg(n)(x) = f(g(n - 1)(x)) forn > 0
求g(n)(x) modulo109 + 7
解题思路:(快速幂,逆元)
g(0)(x) = x
g(1)(x) = A* x + B
g(2)(x) = (A^2) * x + A * B + B
g(3)(x) = (A^3) * x + (A ^ 2)*B + A * B + B
g(n)(x) = (A^n) * x + (A ^ (n-1))*B + ... + A * B + B
所以当 A ≠ 1 时, g(n)(x) = (A^n) * x + B * ((A ^ n - 1) / (A - 1))
当 A = 1时,g(n)(x) = x + n * B
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <map>
#include <cmath>
#include <cctype>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
const ull mod = 1e9 + 7;
const int INF = 0x7fffffff;
ull A, B, n, x;
ull Pow(ull x, ull n);
int main()
{
#ifdef __AiR_H
freopen("in.txt", "r", stdin);
#endif // __AiR_H
scanf("%I64d%I64d%I64d%I64d", &A, &B, &n, &x);
if (A == 1) {
printf("%I64d\n", (x + ((n%mod) * B) % mod) % mod);
} else {
ull ans = Pow(A, n) * x % mod;
ans += (Pow(A, n) - 1) * Pow(A-1, mod-2) % mod * B;
ans %= mod;
printf("%I64d\n", ans);
}
return 0;
}
ull Pow(ull x, ull n)
{
ull ret = 1;
ull t = x % mod;
while (n) {
if (n&1) {
ret = (ret * t) % mod;
}
t = (t * t) % mod;
n >>= 1;
}
return ret;
}
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <map>
#include <cmath>
#include <cctype>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
const ll mod = 1e9 + 7;
const int INF = 0x7fffffff;
ll X, Y;
ll Pow(ll x, ll n);
ll Ext_Gcd(ll a, ll b);
int main()
{
#ifdef __AiR_H
freopen("in.txt", "r", stdin);
#endif // __AiR_H
ll A, B, n, x;
scanf("%I64d%I64d%I64d%I64d", &A, &B, &n, &x);
ll ans = 0;
if (A == 1) {
ans = (x + ((n%mod) * B)%mod)%mod;
} else {
ans = Pow(A, n) * x % mod;
Ext_Gcd(A-1, mod);
while (X < 0) {
X += mod;
}
ans += (Pow(A, n) - 1) * X % mod * B;
ans %= mod;
}
printf("%I64d\n", ans);
return 0;
}
ll Pow(ll x, ll n)
{
ll ret = 1;
ll t = x % mod;
while (n) {
if (n & 1) {
ret = (ret * t) % mod;
}
n >>= 1;
t = (t * t) % mod;
}
return ret;
}
ll Ext_Gcd(ll a, ll b)
{
if (b == 0) {
X = 1;
Y = 0;
return a;
}
ll d = Ext_Gcd(b, a%b);
ll t = X;
X = Y;
Y = t - a/b*Y;
return d;
}
HDU 5685 Problem A
解题思路:
大字符串位置 a 到 位置 b 这段的哈希值等于 (H(b) / H(a - 1)) mod 9973
然后就是求逆元了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <map>
#include <cmath>
#include <cctype>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
const int mod = 9973;
const int INF = 0x7fffffff;
const int maxn = 1e5 + 10;
char s[maxn];
int H[maxn];
int N;
int Quick_Pow(int x, int n);
int main()
{
#ifdef __AiR_H
freopen("in.txt", "r", stdin);
#endif // __AiR_H
while (scanf("%d%s", &N, s) != EOF) {
int len = strlen(s);
H[0] = 1;
for (int i = 0; i < len; ++i) {
H[i+1] = H[i] * (s[i] - 28) % mod;
}
int a, b;
while (N--) {
scanf("%d%d", &a, &b);
printf("%d\n", H[b] * Quick_Pow(H[a-1], mod-2) % mod);
}
}
return 0;
}
int Quick_Pow(int x, int n)
{
int ret = 1;
int t = x % mod;
while (n) {
if (n & 1) {
ret = ret * t % mod;
}
t = t * t % mod;
n >>= 1;
}
return ret;
}