前话——何为逆元?
乘法逆元:
- 每个 a 有且仅有一个 x ,使得ax Ξ 1 (mod p),且gcd(a, p) = 1,x称为a的逆元
或者说:
- ax Ξ 1 (mod p):x是a的逆元
- 一个数a有逆元的充分必要条件:gcd(a, m) = 1,逆元唯一存在
- 思路:
一:
a,b都是大数,所以我们怎么处理这两个数呢?这里就用到了两个取模的性质
(1) (a * b) % p = (a % p) * (b % p) % p
(2) (a ^ b) % p = ((a % p) ^ b) % p
具体:
一个大数来取模,我们可以想想除法的实现过程,是不是从高位到低位依次去除以除数,余数乘10加上下一位再继续除以除数,直到被除数的最后一位为止。
#####举个例子:1234 % 7
12 % 7 = 5 (商1)
53 % 7 = 4 (商7)
44 % 7 = 2 (商6)
————————1234 % 7 = 2
二:
除数b为0的时候是不存在答案的
费马小定理求逆元
证明
由a^(p-1) Ξ 1(mod p)
得a^(p-2) Ξ (1 / a)(mod p)
即(1 / a)(mod p) = a^(p-2) % p
于是得到:a^(p-2)为a的逆元
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <list>
#include <map>
#define INF 0x3f3f3f3f
#define P(x) x>0 ? x : 0
#define MID l + r >> 1
#define lsn rt << 1
#define rsn rt << 1 | 1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define lowbit(x) x & (-x)
using namespace std;
typedef long long ll;
typedef vector<int>:: iterator VITer;
const int maxN = 1e6 + 5;
const ll m = 19260817;
ll fast_power(ll x, ll y)
{
ll base = x, ans = 1;
while(y)
{
if(y & 1)
ans = (ans % m) * (base % m) % m;
base = (base % m) * (base % m) % m;
y >>= 1;
}
return ans % m;
}
ll read(char *str)
{
ll ans = 0;
ll len = strlen(str);
for(ll i = 0; i < len ; i ++)
ans = (ans * 10 + (str[i] - '0') ) % m;
return ans;
}
int main()
{
char stra[maxN], strb[maxN];
while(~ scanf("%s%s", stra, strb))
{
ll a = read(stra);
ll b = read(strb);
if(! b)
{
printf("Angry!\n");
continue;
}
ll b_inverse = fast_power(b, m - 2);
printf("%lld\n", a * b_inverse % m);
}
return 0;
}
扩展欧几里德求逆元
证明
给定质数p,设a的逆元为x
有ax Ξ 1 (% p)
即ax % p = 1
设ax = py + 1
则ax - py = 1 = gcd(a,p)
于是可以用扩展欧几里德求exgcd(a,p), 得到逆元x
注意为了防止负数出现,这样处理:x = (x % p + p) % p
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <list>
#include <map>
#define INF 0x3f3f3f3f
#define P(x) x>0 ? x : 0
#define MID l + r >> 1
#define lsn rt << 1
#define rsn rt << 1 | 1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define lowbit(x) x & (-x)
using namespace std;
typedef long long ll;
typedef vector<int>:: iterator VITer;
const int maxN = 1e6 + 5;
const ll m = 19260817;
ll x, y;
ll exgcd(ll a, ll b)
{
if( ! b ) { x = 1; y = 0; return a;}
ll d = exgcd(b, a % b);
ll tx = y;
ll ty = x - (a / b) * y;
x = tx;
y = ty;
return d;
}
ll read(char *str)
{
ll ans = 0;
ll len = strlen(str);
for(ll i = 0; i < len ; i ++)
ans = (ans * 10 + (str[i] - '0') ) % m;
return ans;
}
int main()
{
char stra[maxN], strb[maxN];
while(~ scanf("%s%s", stra, strb))
{
ll a = read(stra);
ll b = read(strb);
if(! b)
{
printf("Angry!\n");
continue;
}
ll d = exgcd(b, m);
ll b_inverse = (x % m + m) % m;
printf("%lld\n", a * b_inverse % m);
}
return 0;
}