来让我们看看大佬是怎么写的 注:这个dalao是真牛逼 数论很多东西都能用
《什么是数学》《怎样解题》
在讲述这节知识前我们先引入一些知识方便使用
以后出现(mod p)就表示这个公式是在求余p的条件下成立
1 12≡ 5( mod 7 )表示在余7的情况下12和5是一样的
a ≡ b( mod c ) m ≡ n( mod c ) 那么a + m ≡ b + n( mod c )
( a - b ) % c = [ (a % c - b % c ) + c ]%c
( a + b) %c = (a%c + b%c) %c
幺元 在一份封闭的运算系统内 设其为e 若e*a=a a*e=a 那么e就是这个运算系统内的幺元 (类似于单位元 单位向量
逆元 若 a*b=1 那么a和b互为逆元
如果 a*x = 1 那么x是a的倒数,x = 1/a 但是a如果不是1,那么x就是小数 那数论中,大部分情况都有求余,所以现在问题变了 a*x = 1 (mod p) 那么x一定等于1/a吗 不一定 所以这时候,我们就把x看成a的倒数,只不过加了一个求余条件,所以x叫做 a关于p的逆元
比如2 * 3 % 5 = 1,那么3就是2关于5的逆元,或者说2和3关于5互为逆元 这里3的效果是不是跟1/2的效果一样,所以才叫数论倒数
a的逆元,我们用inv(a)来表示
那么(a / b) % p = (a * inv(b) ) % p = (a % p * inv(b) % p) % p
判断一个数能不能被3整除把它各个位上的数相加余3
费马小定理
a^(p-1) ≡1 (mod p) a^(p-2) ≡ inv(a) (mod p) 所以inv(a) = a^(p-2) (mod p) a和p互素
EXgcd(拓展欧几里得)
ax+by=gcd(a,b) 贝祖等式
a,b不全为0
ax1+by1=bx2+(a-a/b*b)y2
x1=y2;
y1=x2-(a/b)y2;
拓展欧几里得求出来的最小逆元大概率是负数
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);
}
#include<cstdio>
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;}
else{
ex_gcd(b, a % b, y, x, d);
y -= x * (a / b);
}
}
LL inv(LL t, LL p){//如果不存在,返回-1
LL d, x, y;
ex_gcd(t, p, x, y, d);
return d == 1 ? (x % p + p) % p : -1;
}
int main(){
LL a, p;
while(~scanf("%lld%lld", &a, &p)){
printf("%lld\n", inv(a, p));
}
}
中国剩余定理给出了以下的一元线性同余方程组:
中国剩余定理说明:假设整数m1,m2, ... ,mn两两互质,则对任意的整数:a1,a2, ... ,an,
方程组(S)
有解,并且通解可以用如下方式构造得到:
设
是整数m1,m2, ... ,mn的乘积,并设
是除了mi以外的n- 1个整数的乘积。
设
这个就是逆元了
通解形式为
在模M的意义下,方程组(S)只有一个解:
//n个方程:x=a[i](mod m[i]) (0<=i<n)
LL china(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;
}
若 m1,m2, ... ,mn两两不保证互质
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
typedef pair<LL, LL> PLL;
PLL linear(LL A[], LL B[], LL M[], int n) {//求解A[i]x = B[i] (mod M[i]),总共n个线性方程组
LL x = 0, m = 1;
for(int i = 0; i < n; i ++) {
LL a = A[i] * m, b = B[i] - A[i]*x, d = gcd(M[i], a);
if(b % d != 0) return PLL(0, -1);//答案不存在,返回-1
LL t = b/d * inv(a/d, M[i]/d)%(M[i]/d);
x = x + m*t;
m *= M[i]/d;
}
x = (x % m + m ) % m;
return PLL(x, m);//返回的x就是答案,m是最后的lcm值
}
排列组合
欧拉函数(暂时不会)
简单概括一下就是求每个数和比他小的数有多少个与他互质(含1)
void eulor()
{
int cnt = 0;
for (i = 2; i < maxn; i++)
{
if (isprime[i] == 0)
{
prime[cnt++] = i;
phi[i] = i - 1;
}
for (j = 0; j < cnt && i * prime[j] < maxn; j++)
{
isprime[i * prime[j]] = 1;
if (i % prime[j] == 0)
phi[i * prime[j]] = phi[i] * prime[j];
else
{
phi[i * prime[j]] = phi[i] * (prime[j] - 1);
}
}
}
}
几何
判断一个点在直线哪一侧
(xp,yp)的点P
设直线是由其上两点(x1,y1),(x2,y2)确定的,直线方向是由(x1,y1)到(x2,y2)的方向。
假设直线方程为:Ax+By+C=0,则有:
A=y2-y1; B=x1-x2; C=x2*y1-x1*y2; D=A*xp+B*yp+C;
若D<0,则点P在直线的左侧;若D>0,则点P在直线的右侧;若D=0,则点P在直线上。