爾雅超星網課答案---【快捷查詢】
數學入門
數論
快速冪
- \(\text{求} a^b \pmod{p}\)
\(\text{當b很大的時候顯然不能列舉,窩們換一種方法思考}\)
\(\text{窩們將b分奇偶討論}\)
-
\(\text{當b為奇數時,} a ^ b = {a ^ {b / 2}} ^ 2 * a\)
-
\(\text{當b為偶數時,} a ^ b = {a ^ {b / 2}} ^ 2\)
\(\text{那麼窩們每次先遞迴求出} a^{b / 2}\) \(\text{然後分情況算就好}\)
\(\text{上部分程式碼}\)
\[\text{看一道題 [HNOI2008]越獄} \]int a, b, p, ans = 1; while(b){ if(b & 1) ans = ans * a % p; a = a * a % p, b >>= 1; } //ans即為答案
\(\text{solution:}\)
\(\text{直接做的話是不是要分很多種情況而且還要容斥,不妨考慮反過來做}\)
\(\text{窩們考慮不會發生越獄的情況,那麼每個位置與他相鄰兩個信仰宗教一定不同}\)
\(\text{那麼當前位置有m種選擇則剩下的位置會有}m - 1\text{種選擇}\)
\(\text{所以答案為} m ^ n - m * {(m - 1)} ^ {n - 1}\)
質數(~~~~)
\(\text{質數的定義就不說了,記一下質數的篩法}\)
\(\text{首先判斷一個數是否是質數注意} \sqrt{n}\)
- \(\text{埃氏篩法複雜度} O(n loglog_n)\)
\(\text{找到每一個質數將他的倍數打標記, 程式碼就不貼了}\)
- \(\text{尤拉篩(線性篩)複雜度} O(n)\)
\(\text{窩們可以發現埃氏篩法種有很多數是重複篩的,於是窩們可以用最小的素數去把每一位篩掉}\)
\(\text{窩們具體看程式碼}\)
is_prime[1] = 0; mem(is_prime, true); for(int i = 2; i <= n; i++){ if(is_prime[i]) prime[++cnt] = i; for(int j = 1; i * prime[j] <= n && j <= cnt; j++){ is_prime[i * prime[j]] = 0; if(i % prime[j] == 0) break;//其他的數留給後面的篩 } }
歐幾里得定理(GCD)
- \(\text{記} gcd(a, b) \text{為a, b的最大公約數} (a \leq b)\)
\(\text{窩們會發現一些優美的性質:}\)
\(gcd(a, b) = gcd(a, a + b) = gcd(a, b - a)\)
\(\text{為什麼呢?}\)
\(\text{事實上,窩們可以證明:} gcd(a, b) = gcd(a, b + t * a) (t \leq \lfloor \frac{b}{a} \rfloor)\)
- \(\text{窩們先證明} gcd(a, b) | gcd(a, b + t * a)\)
\(\text{令} gcd(a, b) = d, a = dx, b = dy\)
\(gcd(a, b) \equiv 0 \pmod{d}\)
\(gcd(a, b + t * a) \equiv gcd(dx, dy + t * dx) \equiv dgcd(x, y + tx) \equiv 0 \pmod{d}\)
\(\text{得證,反過來一樣地證一遍就可以得出} gcd(a, b) = gcd(a, b + t * a)\)
\(\text{實際上就有}\) $gcd(a, b) = gcd(b, a \(%\) b) \text{就是輾轉相除法}$
\(\text{窩們會發現每次取模至少縮小一半所以複雜度是}\) \(O(log(n))\)
擴充套件歐幾里得定理
\(\text{上面窩們已經證明了歐幾里得定理,那麼下面來看這樣一個問題}\)
\[ax + by = gcd(a, b) \]\(\text{求最小整數x, y}\)
\(\text{根據上面的歐幾里得定理,窩們可以知道這個方程等價於}\)
\[bx + (a \mod b)y = gcd(a, a \mod b)\text{(其中}a \mod b = a - \lfloor \frac{a}{b} \rfloor * b) \]\(\text{把柿子化開有} ay + b(1 - \lfloor \frac{a}{b} \rfloor) x = gcd(a, a \mod b)\)
\(\text{假設這個柿子的解為}x_0,y_0 \text{哪原方程的解為} x = y_0, y = x_0 - \lfloor \frac{a}{b} \rfloor * x_0\)
\(\text{那麼最後已知遞迴求會到}a = 1, b = 0 \text{的境地,哪這時的一組特解解為}\)
\[x = 1, y = 0 \]- \(\text{那麼對於不定方程} ax + by = c(gcd(a, b) | c)\)
\(\text{先求出} ax + by = gcd(a, b) \text{的一組解}\)
\(\text{兩邊同乘} \frac{c}{gcd(a, b)} \text{有} ax * \frac{c}{gcd(a, b)} + by * \frac{c}{gcd(a, b)} = c\)
\(\text{就把x, y都乘上這個數不就好了}\)
逆元(模意義下的倒數)
\(\text{眾所周知除以一個數等於乘他的倒數,但在模意義下可能會變成小數,怎麼辦呢?}\)
\(\text{這是窩們引入逆元的概念,即除以一個數等於乘以這個數在模p意義下的逆元}\)
\(\text{符號表達一下就是} x \equiv \frac{1}{x} \pmod{p}\Leftrightarrow ax \equiv 1 \pmod{p}\) \(\text{a就是x在模p意義下的逆元}\)
\(\text{下面引入幾種逆元的求法:}\)
- \(\text{費馬小定理求逆元}\)
\(\text{費馬小定理即} a ^ {p - 1} \equiv 1 \pmod{p} \text{(p為質數)(不會證QAQ)}\)
\(\text{兩邊除以a有} a ^ {p - 2} \equiv \frac{1}{a} \pmod{p} \text{所以} a ^ {p - 2} \text{就是a在模p意義下的逆元}\)
\(\text{快速冪亂搞一下就好啦}\)
只適用於模數為質數的情況
- \(\text{exgcd求逆元}\)
\(\text{解方程組} ax \equiv 1 \pmod{p}\)
\(\Leftrightarrow ax + py \equiv 1 \pmod{p}\)
\(\text{就帶到exgcd中求不定方程} ax + py = 1 \text{的解就好啦}\)
要注意的是,這裡必須滿足 gcd(a, p) = 1
- \(\text{線性遞推逆元}\)
\(\text{窩們令} p = ki + b \text{則} kt + b \equiv 0 \pmod{p}\)
\(\text{移向有} b \equiv -ki \pmod{p}\)
\(\text{兩邊同時除以i, b有} \frac{1}{i} \equiv - \frac{k}{b} \pmod{p} \text{其中}k = \lfloor \frac{p}{i} \rfloor, b = p \mod i\)
\(\text{程式碼如下:}\)
inv[1] = 1;
rep(i, 2, n) inv[i] = 1ll * (p - p / i) * inv[p % i] % p;
- \(\text{遞推階乘逆元}\)
\(\text{注意到階乘有} f[i + 1] \equiv f[i] * (i + 1) \pmod{p}\)
\(\frac{1}{f[i + 1]} \equiv \frac{1}{f[i]} * \frac{1}{i + 1} \text{所以先線性遞推再隨便亂搞就好了}\)
中國剩餘定理(孫孫定理)
\(\text{解方程組}\)
\[\begin{cases} x \equiv a_1 \pmod{p_1}\\ x \equiv a_2 \pmod{p_2}\\ .\\ .\\ .\\ x \equiv a_n \pmod{p_n}\\ \end{cases} \]\(\text{其中} gcd(p_1, p_2, ..., p_n) = 1\)
\(\text{考慮構造答案}\)
\(\text{令}M = \prod_{i = 1} ^ n p_i, M_i = \frac{M}{p_i}, t_i \text{為} M_i \text{在模}p_i \text{意義下的逆元}\)
\(\text{會發現}t_i * M_i * a_i \equiv a_i \pmod{p_i}\)
\(\text{對於} \forall j \not = i, pj | M_i \therefore t_i * M_i * a_i \equiv 0 \pmod{p_j}\)
\(\therefore Ans = \sum_{i = 1} ^ n t_i * M_i * a_i\)
\(\text{要最小就模M一下就好}\)
擴充套件中國剩餘定理(EXCRT)
- 解如下方程組:
- \(\text{(其中模數不一定互質)}\)
\(\text{對於這個方程,窩們不能直接套用CRT的方法來求解}\)
\(\text{因為上面窩們構造的方程中有一步是這樣的}\)
\(\text{對於} \forall \text{i窩們要找到x使得} M_i * x \equiv 1 \pmod{p_i}\)
\(\text{對於這個同餘方程,窩們是通過exgcd來求解x回想我們求解的過程}\)
\(\text{是通過建立不定方程} M_ix+p_iy=1 \text{來求解答案}\)
\(\text{但是前提是要} gcd(M_i, p_i) = 1\)
\(\text{這裡的} p_i \text{不兩兩互質就不一定能達到這個前提}\)
\(\text{窩們考慮換一種方法來求解}\)
\(\text{先單獨考慮前兩項則有}\)
\(\text{令} x = p_1 * k_1 + a_1 = p_2 * k_2 + a_2\)
\(p_2 * k_2 - p_1 * k_1 = a_1 - a_2\)
\(\text{換一下符號有} p_2 * k_2 + p_1 * k_1 = a_1 - a_2\)
\(\text{像極了exgcd求不定方程} ax+by=gcd(a, b) \text{的形式}\)
\(\text{所以我們先求出不定方程為} p_2 * k_2 + p_1 * k_1 = gcd(p_1, p_2) \text{的解}\)
\(\text{然後將得到的} k_1 k_2 \text{乘上} \frac{a_1 - a_2}{gcd(p_1, p_2)} \text{就是一組解}\)
- \(\text{注意如果} gcd(p_1, p_2) \not| a_1 - a_2 \text{則無解}\)
\(\text{然後我們就可以反推出一組特解} x_0\) \(\text{滿足第一二個柿子}\)
\(x_0 = -k_1 * p_1 + a_1 \text{(換了符號所以k等價於-k)}\)
\(\text{另外,窩們吧exgcd算出來的解乘的時候,注意是乘} \frac{a_1 - a_2}{gcd(p_1, p_2)}\)
\(\text{後面的}a_1 a_2 \text{一定不能反,否則就相當於要將x用y代替,可以試著反過來理解一下}\)
\(\text{然後可以知道通解就是} x = x_0 + t * lcm(p_1, p_2)\)
\(\text{改寫一下柿子就成了} x \equiv x_0 \pmod{lcm(p_1, p_2)}\)
\(\text{那不就那這個柿子和下一個柿子去做一樣的東西就好了!!!}\)
- \(\text{注意一下我們調換順序的地方,程式碼實現的時候要注意,還要記得取模}\)
#include<bits/stdc++.h>
using namespace std;
#define maxn 100000 + 5
#define maxm
#define ls (p << 1)
#define rs (p << 1 | 1)
#define lb(x) (x & (-x))
#define mid ((l + r) >> 1)
#define inf 123456789
#define iinf 10000000000000000
#define mod 1000000007
#define re register
#define il inline
#define int long long
#define rep(i, l, r) for(re int i = l; i <= r; ++i)
#define dep(i, l, r) for(re int i = r; i >= l; --i)
#define nxt(i, u) for(re int i = h[u]; i; i = e[i].next)
#define mem(f, x) memset(f, x, sizeof(f))
#define file(a) freopen(#a".in", "r", stdin); freopen(#a".out", "w", stdout);
typedef long long ll;
typedef double D;
int n, M, ans, x, y;
int p[maxn], a[maxn];
int read(){
char c; int x = 0, f = 1;
c = getchar();
while(c > '9' || c < '0'){ if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9'){ x = (x << 3) + (x << 1) + c - '0'; c = getchar();}
return x * f;
}
void exgcd(int a, int b, int &x, int &y){
if(!b){ x = 1, y = 0; return;}
exgcd(b, a % b, y, x), y -= a / b * x;
}
int gcd(int a, int b){ return !b ? a : gcd(b, a % b);}
int mul(int a, int b, int Mod){
int ans = 0;
while(b){
if(b & 1) ans = (ans + a) % Mod;
a = (a + a) % Mod, b >>= 1;
}
return ans;
}
signed main(){
//file(data);
n = read();
rep(i, 1, n) p[i] = read(), a[i] = read();
M = p[1], ans = a[1];
rep(i, 2, n){
exgcd(M, p[i], x, y); int Gcd = gcd(M, p[i]), c = (ans % p[i] - a[i] % p[i] + p[i]) % p[i];
if(c % Gcd){ puts("-1"); return 0;}
x = mul(x, c / Gcd, p[i]); //mul裡面的x一定不能取模,否則就會算反
ans -= M * x, M = M / Gcd * p[i], ans = (ans % M + M) % M;
}
printf("%lld", (ans % M + M) % M);
return 0;
}
BSGS(大步小步)
\(\text{求} y^x \equiv z \pmod{p} \text{的最小正整數x(p為質數)}\)
\(\text{令} m = \sqrt p, x = mi - k (0 \leq k \leq m - 1)\)
\(\text{柿子變成} y ^ {mi} \equiv zy ^ k \pmod{p}\)
\(O(\sqrt p)\text{地暴力列舉k,開個map來存右邊這個在模p意義下的值}\)
\(\text{然後窩們知道當p為質數是} \varphi(p) = p - 1\)
\(\text{由尤拉定理} a ^ b \equiv a ^ {b \% \varphi(p)} \pmod{p}\)
\(\text{所以當mi} \ge p\text{時就會重複地算}\)
\(\text{於是i只用列舉到m就好,然後在map裡判斷一下,複雜度} O(\sqrt n log n)\)
p = read(), b = read(), n = read(); M = sqrt(p);
if(b % p == 0 && n % p != 0){ puts("no solution"); return 0;}
if(n % p == 1){ puts("0"); return 0;}
if(b % p == 0 && n % p == 0){ puts("1"); return 0;}
rep(i, 1, M - 1){
int now = n * Q(b, i, p) % p; //printf("now here is %lld\n", now);
if(!a[now]) a[now] = i;
}
rep(i, 1, M){
int now = Q(b, i * M, p); //printf("asdsad %lld\n", now);
if(a[now]){ printf("%lld", i * M - a[now]); return 0;}
}
puts("no solution");
\(b = y,n = z\)
組合數學
盧卡斯定理
\(C ^ m_n \equiv C ^ {m \% p}_{n \%p} * C ^ {m / p}_{n / p} \pmod{p}\)
\(\text{不會證QAQ}\)
ll c(ll n, ll m, ll p){
if(m > n) return 0ll;
else return ((f[n] * qpow(f[m], p - 2, p)) % p * qpow(f[n - m], p - 2, p)) % p;
}
ll lucas(ll n, ll m, ll p){
if(m == 0) return 1ll;
return c(n % p, m % p, p) * lucas(n / p, m / p, p) % p;
}
\[\text{帶修,後續要放一些題}
\]