來讓我們看看大佬是怎麼寫的 注:這個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在直線上。