1.逆元
逆元怎么求 (a和p互质,a才有关于b的逆元)
方法一:
费马小定理
a^(p-1)=1(mod p)
两边同除以a
a^(p-2)=inv(a)(mod p)
inv(a)=a^(p-2)(mod p)
可以用快速幂求解 复杂度 log n;
LL pow_mod(LL a, LL b, LL p){//a的b次方求余p
LL ret = 1;
while(b){
if(b & 1) ret = (ret * a) % p;
a = (a * a) % p;
b >>= 1;
}
return ret;
}
LL Fermat(LL a, LL p){//费马求a关于b的逆元
return pow_mod(a, p-2, p);
}
方法二:
扩展欧几里德算法
a*x+b*y=1
如果ab互质,则有解。并且这个解的X是a关于b的逆元,解的Y是b关于x的逆元
a*x % b + b*y % b = 1 % b
a*x % b = 1 % b
a*x = 1 (mod b)
代码:
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include <cmath>
using namespace std;
typedef long long LL;
void ex_gcd(LL a,LL b,LL &x,LL &y,LL &d)
{
if(!b)
{
d=a;x=1;y=0;
return;
}
ex_gcd(b,a%b,x,y,d);
int t=x;x=y;y=t-(a/b)*y;
return;
}
LL inv(LL t, LL p)
{
LL d, x, y;
ex_gcd(t, p, x, y, d);
if(d==1)
return (x % p + p) % p;
else
return -1;
}
int main()
{
LL n,m;
while(~scanf("%lld%lld", &n, &m))
{
printf("%lld\n", inv(n, m));
}
return 0;
}
中国剩余定理
能求解什么问题呢?
问题:
一堆物品
3个3个分剩2个
5个5个分剩3个
7个7个分剩2个
问这个物品有多少个?
解这题,我们需要构造一个答案
我们需要构造这个答案
5*7*inv(5*7, 3) % 3 = 1
3*7*inv(3*7, 5) % 5 = 1
3*5*inv(3*5, 7) % 7 = 1
这3个式子对不对,别告诉我逆元你忘了(*´∇`*),忘了的人请翻阅前几章复习
然后两边同乘你需要的数
2 * 5*7*inv(5*7, 3) % 3 = 2
3 * 3*7*inv(3*7, 5) % 5 = 3
2 * 3*5*inv(3*5, 7) % 7 = 2
令
a = 2 * 5*7*inv(5*7, 3)
b = 3 * 3*7*inv(3*7, 5)
c = 2 * 3*5*inv(3*5, 7)
那么
a % 3 = 2
b % 5 = 3
c % 7 = 2
其实答案就是a+b+c
因为
a%5 = a%7 = 0 因为a是5的倍数,也是7的倍数
b%3 = b%7 = 0 因为b是3的倍数,也是7的倍数
c%3 = c%5 = 0 因为c是3的倍数,也是5的倍数
所以
(a + b + c) % 3 = (a % 3) + (b % 3) + (c % 3) = 2 + 0 + 0 = 2
(a + b + c) % 5 = (a % 5) + (b % 5) + (c % 5) = 0 + 3 + 0 = 3
(a + b + c) % 7 = (a % 7) + (b % 7) + (c % 7) = 0 + 0 + 2 = 2
你看你看,答案是不是a+b+c(。・ω・)ノ゙,完全满足题意
但是答案,不只一个,有无穷个,每105个就是一个答案(105 = 3 * 5 * 7)
根据计算,答案等于233,233%105 = 23
如果题目问你最小的那个答案,那就是23了
例题: 51Nod - 1079
一个正整数K,给出K Mod 一些质数的结果,求符合条件的最小的K。例如,K % 2 = 1, K % 3 = 2, K % 5 = 3。符合条件的最小的K = 23。
Input
第1行:1个数N表示后面输入的质数及模的数量。(2 <= N <= 10)
第2 - N + 1行,每行2个数P和M,中间用空格分隔,P是质数,M是K % P的结果。(2 <= P <= 100, 0 <= K < P)
Output
输出符合条件的最小的K。数据中所有K均小于10^9。
Sample Input
3
2 1
3 2
5 3
Sample Output
23
代码如下:
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include <cmath>
using namespace std;
typedef long long LL;
void ex_gcd(LL a,LL b,LL &x,LL &y,LL &d)
{
if(!b)
{
d=a;x=1;y=0;
return;
}
ex_gcd(b,a%b,x,y,d);
int t=x;x=y;y=t-(a/b)*y;
return;
}
LL inv(LL t, LL p)
{
LL d, x, y;
ex_gcd(t, p, x, y, d);
if(d==1)
return (x % p + p) % p;
else
return -1;
}
LL C(int n, LL *a, LL *m){
LL M = 1, ret = 0;
for(int i = 0; i < n; i ++) M *= m[i];
for(int i = 0; i < n; i ++){
LL w = M / m[i];
ret = (ret + w * inv(w, m[i]) * a[i]) % M;
}
return (ret + M) % M;
}
int main()
{
LL n,m,a[10000],b[10000];
scanf("%lld", &n);
for(int i=0;i<n;i++)
scanf("%lld%lld",&a[i],&b[i]);
printf("%lld\n", C(n,b,a));
return 0;
}