【簡單數論】(模運算,快速冪,乘法逆元,同余,exgcd,gcd,歐拉函數,質數,歐拉篩,埃式篩,調和級數枚舉,約數,組合數)

數論

模運算

  • a m o d b = a ? ? a / b ? × b a\ mod \ b = a - \lfloor a / b \rfloor \times b a?mod?b=a??a/b?×b

  • n m o d p n \ mod\ p n?mod?p得到的結果的正負至于被除數 n n n有關

image-20250404133801773

模運算的性質:

( a + b ) m o d m = ( ( a m o d m ) + ( b m o d m ) ) m o d m (a + b)\ mod\ m = ((a\ mod\ m) + (b\ mod\ m))\ mod\ m (a+b)?mod?m=((a?mod?m)+(b?mod?m))?mod?m

( a ? b ) m o d m = ( ( a m o d m ) ? ( b m o d m ) ) m o d m (a - b)\ mod\ m = ((a\ mod\ m) - (b\ mod\ m))\ mod\ m (a?b)?mod?m=((a?mod?m)?(b?mod?m))?mod?m = ( ( a m o d m ) ? ( b m o d m ) + m ) m o d m ((a\ mod\ m) - (b\ mod\ m) + m)\ mod\ m ((a?mod?m)?(b?mod?m)+m)?mod?m

( a × b ) m o d m = ( ( a m o d m ) × ( b m o d m ) ) m o d m (a \times b)\ mod\ m = ((a\ mod\ m) \times (b\ mod\ m))\ mod\ m (a×b)?mod?m=((a?mod?m)×(b?mod?m))?mod?m

但是除法例外,除法的取模需要用到逆元。

計算減法的時候,通常需要加上模數,防止出現負數。

快速冪

快速求解 a b m o d p a^b \ mod \ p ab?mod?p,可以采用二進制拼湊的思想

對于 b b b,它可以看成一個二進制數,可以寫成 2 2 2的冪相加的形式,那么 a b a^b ab可以寫成 a ( 2 i + 2 j + . . . + 2 k ) = a 2 i × a 2 j × . . . × a 2 k ( i , j , k ∈ S , 其中集合 S 為 b 轉換成二進制后位置上是 1 的位置 ) a^{(2^{i} + 2^j + ... + 2^k)} = a^{2^i}\times a^{2^j} \times ... \times a^{2^k} \ (i, j, k \in S,其中集合S為b轉換成二進制后位置上是1的位置) a(2i+2j+...+2k)=a2i×a2j×...×a2k?(i,j,kS,其中集合Sb轉換成二進制后位置上是1的位置)

我們只需計算的同時預處理每一項 a 2 i a^{2^i} a2i即可

using ll = long long;
ll qmi(ll a, ll b, ll c){ll res = 1;while(b){if(b & 1 == 1) res = res * a % c;a = a * a % c;b >>= 1;}return res;
}

乘法逆元

a × x ≡ 1 ( m o d b ) a \times x \equiv 1 \ (mod \ b) a×x1?(mod?b),且 a a a b b b互質,我們定義 x x x a a a的逆元,記為 a ? 1 a^{-1} a?1, x x x可稱為 a a a在模 b b b意義下的倒數

對于 a b m o d p \frac{a}{b} \ mod \ p ba??mod?p,我們可以求出 b b b m o d p mod \ p mod?p意義下的逆元,然后乘上 a a a,再 m o d p mod \ p mod?p即可

注意對于數 a a a在模 p p p意義下的乘法逆元,我們需要確保 a a a p p p互質,此時才有 a a a的乘法逆元 a ? 1 a^{-1} a?1,此條件等價于 p p p是質數

費馬小定理

a p ? 1 ≡ 1 ( m o d p ) a^{p - 1} \equiv 1 \ (mod \ p) ap?11?(mod?p),其中 p p p是素數

費馬小定理求逆元
a × a p ? 2 ≡ 1 ( m o d p ) a \times a^{p - 2} \equiv 1 \ (mod\ p) a×ap?21?(mod?p),根據乘法逆元的定義可知,此時 a a a的逆元是 a p ? 2 a^{p - 2} ap?2

ll inv(ll a, ll p){return qmi(a, p - 2, p);
}

擴展歐幾里得求逆元

根據逆元的定義 a x ≡ 1 ( m o d p ) ax \equiv 1 \ (mod \ p) ax1?(mod?p),我們得到方程: a x ? 1 = y p ax - 1 = yp ax?1=yp a x ? 1 ax - 1 ax?1 p p p的倍數),則 a x + p y = 1 ax + py = 1 ax+py=1

解方程得 x m o d p x \ mod \ p x?mod?p得到的就是 a a a的乘法逆元,同時逆元存在的條件是 g c d ( a , p ) = 1 gcd(a, p) = 1 gcd(a,p)=1

求階乘的乘法逆元

同余

兩個整數 a a a b b b對用一個正整數 m m m取模后余數相同,則稱 a a a b b b對模 m m m同余,記作 a ≡ b ( m o d m ) a \equiv b \ (mod\ m) ab?(mod?m),這意味著 m ∣ ( a ? b ) m\ | \ (a - b) m??(a?b)

同余的性質:

  • 自反性: a ≡ a ( m o d m ) a \equiv a \ (mod\ m) aa?(mod?m)
  • 對稱性:若 a ≡ b ( m o d m ) a \equiv b \ (mod \ m) ab?(mod?m),則 b ≡ a ( m o d m ) b \equiv a \ (mod \ m) ba?(mod?m)
  • 傳遞性:若 a ≡ b ( m o d m ) , b ≡ c ( m o d m ) a \equiv b \ (mod\ m), b \equiv c \ (mod\ m) ab?(mod?m),bc?(mod?m),則 a ≡ c ( m o d m ) a \equiv c \ (mod\ m) ac?(mod?m)
  • 同加性:若 a ≡ b ( m o d m ) a \equiv b \ (mod\ m) ab?(mod?m),則 a ± c ≡ b ± c ( m o d m ) a \pm c \equiv b \pm c \ (mod\ m) a±cb±c?(mod?m)
  • 同乘性:若 a ≡ b ( m o d m ) a \equiv b \ (mod\ m) ab?(mod?m),則 a × c ≡ b × c ( m o d m ) a \times c \equiv b \times c \ (mod\ m) a×cb×c?(mod?m),若 a ≡ b ( m o d m ) , c ≡ d ( m o d m ) a \equiv b \ (mod \ m), c \equiv d \ (mod \ m) ab?(mod?m),cd?(mod?m),則 a × c ≡ b × d ( m o d m ) a \times c \equiv b \times d \ (mod\ m) a×cb×d?(mod?m)
  • 同冪性:若 a ≡ b ( m o d m ) a \equiv b \ (mod \ m) ab?(mod?m),則 a c ≡ b c ( m o d m ) a^c \equiv b^c \ (mod\ m) acbc?(mod?m)
  • 不滿足同除性,但是有,若 c a ≡ c b ( m o d m ) ca \equiv cb \ (mod \ m) cacb?(mod?m),則 a ≡ b ( m o d m g c d ( m , c ) ) a \equiv b \ (\ mod \ \frac{m}{gcd(m, c)}) ab?(?mod?gcd(m,c)m?)

擴展歐幾里得定理

對于給定的兩個整數 a a a b b b,必須存在整數 x x x y y y,使得 a × x + b × y = g c d ( a , b ) a \times x + b \times y = gcd(a, b) a×x+b×y=gcd(a,b)

裴蜀定理

方程 a × x + b × y = c a \times x + b \times y = c a×x+b×y=c有整數解的充分必要條件是 c c c g c d ( a , b ) gcd(a, b) gcd(a,b)的倍數

證明:

  • 必要性:令 p = g c d ( a , b ) p = gcd(a, b) p=gcd(a,b),則有 a = p × a ′ a = p \times a' a=p×a b = p × b ′ b = p \times b' b=p×b;則 c = p × ( a ′ x + b ′ y ) c = p \times (a'x + b'y) c=p×(ax+by),即 g c d ( a , b ) gcd(a, b) gcd(a,b)的倍數。

  • 充分性:考慮 g c d gcd gcd的歐幾里得算法。 a , b a, b a,b通過 b , a % b b, a \% b b,a%b的方式一直輾轉下去,最后會出現 p , 0 p, 0 p,0的形式。原因是 0 ≤ a % b ≤ b ? 1 0 \leq a \% b \leq b - 1 0a%bb?1。對于遞歸出口 p , 0 p, 0 p,0,方程 a × p + 0 × y = c a \times p + 0 \times y = c a×p+0×y=c是否存在解呢?顯然有解,由于充分性,這里 a a a c p \frac{c}{p} pc?即可。那么輾轉相除過程中,下面的成立能否推得上面的成立呢?

    • 對于方程 b x 1 + a % b × y 1 = c = a x + b y bx_1 + a \% b \times y_1 = c = ax + by bx1?+a%b×y1?=c=ax+by

    • 左邊 = b x 1 + ( a ? ? a b ? × b ) × y 1 = a y 1 + b x 1 ? ? a b ? × b y 1 = a y 1 + b × ( x 1 ? ? a b ? × y 1 ) = 右邊 = a x + b y 左邊 = bx_1 + (a - \lfloor \frac{a}{b} \rfloor \times b) \times y_1 = ay_1 + bx_1 - \lfloor \frac{a}{b} \rfloor \times by_1 = ay_1 + b \times (x_1 - \lfloor \frac{a}{b} \rfloor \times y_1) = 右邊 = ax + by 左邊=bx1?+(a??ba??×b)×y1?=ay1?+bx1???ba??×by1?=ay1?+b×(x1???ba??×y1?)=右邊=ax+by

      所以找到一組特解: x = y 1 x = y_1 x=y1? y = x 1 ? ? a b ? × y 1 y = x_1 - \lfloor \frac{a}{b} \rfloor \times y_1 y=x1???ba??×y1?,就可以通過最下面的特解推得所有的特解。

    • 對于特解 ( x 0 , y 0 ) (x_0, y_0) (x0?,y0?),設下一組解是 ( x 0 + d 1 , y 0 + d 2 ) (x_0 + d_1, y_0 + d_2) (x0?+d1?,y0?+d2?)

      a × ( x 0 + d 1 ) + b × ( y 0 + d 2 ) = c a \times (x_0 + d_1) + b \times (y_0 + d_2) = c a×(x0?+d1?)+b×(y0?+d2?)=c,又, a × x 0 + b × y 0 = c a \times x_0 + b \times y_0 = c a×x0?+b×y0?=c,則 a d 1 + b d 2 = 0 ad_1 + bd_2 = 0 ad1?+bd2?=0

      故, d 1 d 2 = ? b a = ? b / g c d ( a , b ) a / g c d ( a , b ) \frac{d_1}{d_2} = -\frac{b}{a} = -\frac{b / gcd(a, b)}{a / gcd(a, b)} d2?d1??=?ab?=?a/gcd(a,b)b/gcd(a,b)?

      d 1 = b g c d ( a , b ) d_1 = \frac{b}{gcd(a, b)} d1?=gcd(a,b)b? d 2 = ? a g c d ( a , b ) d_2 = -\frac{a}{gcd(a, b)} d2?=?gcd(a,b)a?,故一般解為:

      x = x 0 + k × b g c d ( a , b ) x = x_0 + k \times \frac{b}{gcd(a, b)} x=x0?+k×gcd(a,b)b? y = y 0 ? k × a g c d ( a , b ) ( k ∈ Z ) y = y_0 - k \times \frac{a}{gcd(a, b)} \ (k \in Z) y=y0??k×gcd(a,b)a??(kZ)

    • 若要求 x x x的最小整數解,則可以通過 ( x 0 m o d ( b g c d ( a , b ) ) + b g c d ( a , b ) ) m o d x 0 (x_0 \ mod \ (\frac{b}{gcd(a, b)}) + \frac{b}{gcd(a, b)}) \ mod \ x_0 (x0??mod?(gcd(a,b)b?)+gcd(a,b)b?)?mod?x0?,原因是 x 0 x_0 x0?的周期是 b g c d ( a , b ) \frac{b}{gcd(a, b)} gcd(a,b)b?,所以可通過取模的方式得到結果

擴展歐幾里得算法

int exgcd(int a, int b, int &x, int &y){if(b == 0){x = 1, y= 0;return a;}int t = exgcd(b, a % b, y, x);y -= a / b * x;return t;
}

GCD

最大公約數:歐幾里得算法,時間復雜度 O ( l o g a ) O(log\ a) O(log?a)

g c d ( a , b ) = g c d ( b , a m o d b ) gcd(a, b) = gcd(b, a\ mod\ b) gcd(a,b)=gcd(b,a?mod?b)

證明如下:

  • p = g c d ( a , b ) p = gcd(a, b) p=gcd(a,b),則有 a = p × a ′ a = p \times a' a=p×a b = p × b ′ b = p \times b' b=p×b g c d ( a ′ , b ′ ) = 1 gcd(a', b') = 1 gcd(a,b)=1

    • a m o d b = a ? ? a / b ? × b = p × a ′ ? p × b ′ × ? a / b ? a\ mod\ b = a - \lfloor a / b \rfloor \times b = p \times a' - p \times b' \times \lfloor a / b \rfloor a?mod?b=a??a/b?×b=p×a?p×b×?a/b?

    • 可以看出, p ∣ b p \ | \ b p??b p ∣ ( a m o d b ) p \ | \ (a \ mod \ b) p??(a?mod?b)

  • 那么 p p p是否是最大公約數呢?即我們需要證明 g c d ( b ′ , a ′ ? b ′ × ? a / b ? ) = 1 gcd(b', a' - b' \times \lfloor a / b \rfloor) = 1 gcd(b,a?b×?a/b?)=1

    • g c d ( b ′ , a ′ ? b ′ × ? a / b ? ) = d gcd(b', a' - b' \times \lfloor a / b \rfloor) = d gcd(b,a?b×?a/b?)=d,則有 b ′ = d × b ′ ′ b' = d \times b'' b=d×b′′ a ′ ? b ′ × ? a / b ? = d × c a' - b' \times \lfloor a / b \rfloor = d \times c a?b×?a/b?=d×c
    • 轉換得到 a ′ = d × c + b ′ × ? a / b ? = d × c + d × b ′ ′ × ? a / b ? a' = d \times c + b' \times \lfloor a / b \rfloor = d \times c + d \times b'' \times \lfloor a / b \rfloor a=d×c+b×?a/b?=d×c+d×b′′×?a/b?
    • 可以發現 d ∣ b ′ d\ |\ b' d??b d ∣ a ′ d\ | \ a' d??a,與上述 g c d ( a ′ , b ′ ) = 1 gcd(a', b') = 1 gcd(a,b)=1矛盾,則命題得證。

歐拉函數

1... N 1...N 1...N中與 N N N互質的數的個數,被稱為歐拉函數,記作 ? ( N ) \phi(N) ?(N)

在唯一分解定理中, N = p 1 a 1 × p 2 a 2 × . . . × p m a m N = p_1^{a_1} \times p_2^{a_2} \times ...\times p_m^{a_m} N=p1a1??×p2a2??×...×pmam??,則 ? ( N ) = N × p 1 ? 1 p 1 × p 2 ? 1 p 2 × . . . × p m ? 1 p m = N × ( 1 ? 1 p 1 ) × ( 1 ? 1 p 2 ) × . . . × ( 1 ? 1 p m ) \phi(N) = N \times \frac{p_1 - 1}{p_1} \times \frac{p_2 - 1}{p_2} \times ... \times \frac{p_m - 1}{p_m} = N \times (1 - \frac{1}{p_1}) \times (1 - \frac{1}{p_2}) \times...\times (1 - \frac{1}{p_m}) ?(N)=N×p1?p1??1?×p2?p2??1?×...×pm?pm??1?=N×(1?p1?1?)×(1?p2?1?)×...×(1?pm?1?)

證明:

先對 N N N分解質因數,得到 N = p 1 a 1 × p 2 a 2 × . . . × p m a m N = p_1^{a_1} \times p_2^{a_2} \times ...\times p_m^{a_m} N=p1a1??×p2a2??×...×pmam??

[ 1 , N ] [1, N] [1,N]中,我們先將所以 p 1 , p 2 , . . . , p m p_1, p_2, ..., p_m p1?,p2?,...,pm?的倍數減掉,再將所有 p i × p j p_i \times p_j pi?×pj?的倍數的數加上,再減去 p i × p j × p k p_i \times p_j \times p_k pi?×pj?×pk?的倍數的數,以此類推。最后剩下的就是與 N N N互質的數的個數。式子表達為 N ? ( N p 1 + N p 2 + . . . + N p m ) + ( N p 1 p 2 + N p 1 p 3 + . . . ) ? ( N p 1 p 2 p 3 + . . . ) . . . N - (\frac{N}{p_1} + \frac{N}{p_2} + ... + \frac{N}{p_m}) + (\frac{N}{p_1p_2} + \frac{N}{p_1p_3} + ... ) - (\frac{N}{p_1p_2p_3} + ...) ... N?(p1?N?+p2?N?+...+pm?N?)+(p1?p2?N?+p1?p3?N?+...)?(p1?p2?p3?N?+...)...

該式就是 N × ( 1 ? 1 p 1 ) × ( 1 ? 1 p 2 ) × . . . × ( 1 ? 1 p m ) N \times (1 - \frac{1}{p_1}) \times (1 - \frac{1}{p_2}) \times...\times (1 - \frac{1}{p_m}) N×(1?p1?1?)×(1?p2?1?)×...×(1?pm?1?)的展開式

公式法求歐拉函數

#include <bits/stdc++.h>
using namespace std;void solve() {int n;cin >> n;auto f = [&](int x) -> int {int res = x;for (int i = 2; i <= x / i; i ++) {if (x % i != 0) continue;res = res / i * (i - 1);while (x % i == 0) x /= i;}  if (x > 1) res = res / x * (x - 1); return res;};cout << f(n) << endl;
}int main() {int t;cin >> t;while (t --) {solve();}return 0;
}

篩法求歐拉函數

對于一個質數 p p p來說, ? ( p ) = p ? 1 \phi(p) = p - 1 ?(p)=p?1

對于每一個數 p r i m e s [ j ] × i primes[j] \times i primes[j]×i來說

  • i % p r i m e s [ j ] = 0 i \% primes[j] = 0 i%primes[j]=0時, i i i中的質因子包括 p r i m e s [ j ] primes[j] primes[j],則有 ? ( p r i m e s [ j ] × i ) = ? ( i ) × p r i m e s [ j ] \phi(primes[j] \times i) = \phi(i) \times primes[j] ?(primes[j]×i)=?(i)×primes[j]
  • i % p r i m e s [ j ] ≠ 0 i \% primes[j] \neq 0 i%primes[j]=0時, i × p r i m e s [ j ] i \times primes[j] i×primes[j]中的質因子既包括 i i i中的質因子,又包括 p r i m e s [ j ] primes[j] primes[j],則有 ? ( p r i m e s [ j ] × i ) = ? ( i ) × p r i m e s [ j ] × ( 1 ? 1 p r i m e s [ j ] ) \phi(primes[j] \times i) = \phi(i) \times primes[j] \times (1 - \frac{1}{primes[j]}) ?(primes[j]×i)=?(i)×primes[j]×(1?primes[j]1?)
#include <bits/stdc++.h>s
using namespace std;#define int long longconst int N = 1000010;
int cnt, primes[N];
bool st[N];
int phi[N];int getEuler(int n) {phi[1] = 1;for (int i = 2; i <= n; i ++) {if (st[i] == false) {primes[cnt ++] = i;phi[i] = i - 1;}for (int j = 0; j < cnt && primes[j] <= n / i; j ++) {st[primes[j] * i] = true;if (i % primes[j] == 0) {phi[i * primes[j]] = phi[i] * primes[j];break;}phi[i * primes[j]] = phi[i] * primes[j] / primes[j] * (primes[j] - 1);}}int res = 0;for (int i = 1; i <= n; i ++) {res += phi[i];}return res;
}signed main() {int n;cin >> n;cout << getEuler(n) << endl;return 0;
}

質數

分解質因數

給定一個數 x x x,由唯一分解定理可知, x = p 1 a 1 × p 2 a 2 × p 3 a 3 . . . ( p 1 < p 2 < p 3 ) x = p_1^{a_1} \times p_2^{a_2} \times p_3^{a_3}...\ (p_1 < p_2 < p_3) x=p1a1??×p2a2??×p3a3??...?(p1?<p2?<p3?),我們從小到大枚舉每一個數,最先整除 x x x的除數 n n n一定是素數。同時將這個數中所有 n n n的因子除干凈,那么下次 x x x被整除時除數也是素數,從而分解了質因數。

#include <bits/stdc++.h>
using namespace std;int main() {int n;cin >> n;for (int i = 0; i < n; i ++) {int x;cin >> x;map<int, int> cnt;vector<int> res;for (int j = 2; j <= x / j; j ++) {if (x % j != 0) continue;res.push_back(j);while (x % j == 0) {cnt[j] ++;x /= j;}}if (x > 1) {res.push_back(x);cnt[x] ++;}for (auto& u : res) {cout << u << " " << cnt[u] << endl;}cout << endl;}return 0;
}

普通篩法

給定一個整數 x x x,并篩掉所有倍數,如 2 x , 3 x , 4 x . . . 2x, 3x, 4x... 2x,3x,4x...

篩完后, v i s [ i ] = f a l s e vis[i] = false vis[i]=false的為素數

這種方法的時間復雜度是 O ( n l o g n ) O(n\ log\ n) O(n?log?n)級別

對于每一個外層循環變量 i i i,內層循環枚舉所有不超過 n n n i i i的倍數,枚舉次數是 ? n i ? \lfloor \frac{n}{i} \rfloor ?in??,又 ? n i ? < n i \lfloor \frac{n}{i} \rfloor < \frac{n}{i} ?in??<in?,有調和級數的漸近公式 ∑ i = 1 n 1 i ≈ l n ( n + 1 ) + 0.577218 \sum^{n}_{i = 1} \frac{1}{i} \approx ln(n + 1) + 0.577218 i=1n?i1?ln(n+1)+0.577218,其中 0.577218 0.577218 0.577218是歐拉常數

所以復雜度是 O ( n l o g n ) O(n\ log\ n) O(n?log?n)級別

雖然這個篩法的時間復雜度很差,但是調和級數枚舉引人深思,這種枚舉方式非常巧妙,而且復雜度僅有 O ( l o g n ) O(log\ n) O(log?n)級別

埃式篩法

在調和級數枚舉的篩法中,我們發現枚舉4的倍數無意義,因為從這里篩掉的數一定從2的倍數里篩掉了,所以我們想到:只用質數去篩

其復雜度只有 O ( n l o g l o g n ) O(n\ log\ log\ n) O(n?log?log?n)

#include <bits/stdc++.h>
using namespace std;const int N = 1e6 + 10;
int cnt, primes[N], n;
bool st[N];int main() {cin >> n;for (int i = 2; i <= n; i ++) {if (st[i]) continue;primes[cnt ++] = i;for (int j = 2 * i; j <= n; j += i) {st[j] = true;}}cout << cnt << endl;return 0;
}

歐拉篩

通過對埃氏篩法的分析,我們發現 6 = 2 × 3 6 = 2 \times 3 6=2×3會被質數 2 2 2 3 3 3各篩一次。一個數有多少個質因子,它就會被篩多少次。那么我們能否讓一個數只被篩掉一次呢?

歐拉篩法可以做到并且每個數會被它的最小質因子篩掉

#include <bits/stdc++.h>
using namespace std;const int N = 1e6 + 10;
int cnt, primes[N], n;
bool st[N];int main() {cin >> n;for (int i = 2; i <= n; i ++) {if (!st[i]) primes[cnt ++] = i; //是素數for (int j = 0; j < cnt && primes[j] <= n / i; j ++) {st[primes[j] * i] = true;if (i % primes[j] == 0) break;}}cout << cnt << endl;return 0;
}
  • x = i × p r i m e s [ j ] x = i \times primes[j] x=i×primes[j]
  • i m o d p r i m e s [ j ] ≠ 0 i \ mod \ primes[j] \neq 0 i?mod?primes[j]=0,則 i i i中沒有 p r i m e s [ j ] primes[j] primes[j]這個質因子。又因為 j j j是從小到大遍歷的,所以 p r i m e s [ j ] < i primes[j] < i primes[j]<i,則 p r i m e s [ j ] primes[j] primes[j] x x x的最小質因子
  • i m o d p r i m e s [ j ] = 0 i \ mod \ primes[j] = 0 i?mod?primes[j]=0 ,說明 p r i m e s [ j ] primes[j] primes[j] i i i的一個質因子。又因為 j j j是從小到大遍歷的,所以 p r i m e s [ j ] primes[j] primes[j] i i i的最小質因子。所以 p r i m e s [ j ] primes[j] primes[j] x x x的最小質因子
  • 綜上所述,每個數都是被其最小質因子 p r i m e s [ j ] primes[j] primes[j]篩掉且只會被篩掉一次

調和級數枚舉模型

內容參考于:[OI&ACM]調和級數枚舉倍數模型 - 知乎
給定一個數 n ( n ≤ 1 0 6 ) n\ (n \leq 10^6) n?(n106),求 [ 1 , n ] [1, n] [1,n]中所有整數 i i i的正因子個數

思路:枚舉 [ 1 , n ] [1, n] [1,n]中的所有數 i i i,對 i i i的所有倍數, i i i 會增加 1 1 1的貢獻。考慮調和級數枚舉:

int d[1000001] = {0}; // 儲存因數倍數,初始全為 0
for (int i = 1; i <= n; i++) // 枚舉 [1, n] 的數
{for (int j = i; j <= n; j += i) // 枚舉 i 的倍數{d[j]++;}
}

時間復雜度為 O ( n l o g n ) O(n \ log\ n) O(n?log?n)級別

下面的題目都應用了該模型,讀者不妨觀看思考

題目1:Problem - D - Codeforces

大意:給定一個長度為 n ( n ≤ 1 0 5 ) n\ (n \leq 10^5) n?(n105)的數組,每次操作可以任取一些位置上的數,并將該位置上的數染成黑色。然后將這些被染成黑色的位置索引的所有倍數染成綠色,每次操作的得分是該數組中黑色和綠色位置上的數的最大值。由于選擇染成黑色的操作有 2 n ? 1 2^n - 1 2n?1種,所以我們要求出所有操作的得分的和

選擇每個數所能得到的最大值是容易處理的。

vector<int> maxv(n + 1, 0);
for (int i = 1; i <= n; i ++) {for (int j = i; j <= n; j += i) {maxv[i] = max(maxv[i], a[j]);}
}

我們明確 m a x v maxv maxv數組的含義:選擇第 i i i上的數,將其涂成黑色,并將其索引的倍數涂成綠色,所能得到的最大值。假設有這樣的 m a x v maxv maxv數組, m a x v = [ 1 , 6 , 7 , 3 ] maxv = [1, 6, 7, 3] maxv=[1,6,7,3] 1 1 1貢獻了 1 1 1次, 3 3 3貢獻了 2 2 2次, 6 6 6貢獻了 4 4 4次, 7 7 7貢獻了 8 8 8次。這是因為:對于第一個位置上的數,我們有如下的選擇方式 [ 1 ] , [ 1 , 2 ] , [ 1 , 3 ] , [ 1 , 4 ] , [ 1 , 2 , 3 ] , [ 1 , 2 , 4 ] , [ 1 , 3 , 4 ] , [ 1 , 2 , 3 , 4 ] ( [ 1 , 3 , 4 ] 表示我們選擇第 1 , 3 , 4 個數字,其余同理 ) [1], [1, 2], [1, 3], [1, 4], [1, 2, 3],[1, 2, 4], [1, 3, 4], [1, 2, 3, 4]\ ([1, 3, 4]表示我們選擇第1,3,4個數字,其余同理) [1],[1,2],[1,3],[1,4],[1,2,3],[1,2,4],[1,3,4],[1,2,3,4]?([1,3,4]表示我們選擇第134個數字,其余同理),由于 1 1 1是最小的,在如下選擇中只貢獻了 1 1 1次,就是選擇方式為 [ 1 ] [1] [1]的時候。所以我們可以將 m a x v maxv maxv數組排序并用貢獻法求出答案

sort(maxv.begin() + 1, maxv.begin() + n + 1);
LL res = 0, pow2 = 1;	
for (int i = 1; i <= n; i ++) {res = (res % mod + maxv[i] * pow2 % mod) % mod;pow2 = pow2 * 2 % mod;
}cout << res << endl;

題目2:Problem - D - Codeforces

大意:給定一個數組 a a a,其長度為 n n n,其中 1 ≤ n ≤ 1 0 6 1 \leq n \leq 10^6 1n106 1 ≤ a i ≤ n 1 \leq a_i \leq n 1ai?n。若不存在 k , ( 1 ≤ k ≤ n ) k,(1 \leq k \leq n) k(1kn)使得 a k ∣ a i a_k \ | \ a_i ak???ai? a k ∣ a j a_k \ | \ a_j ak???aj?,那么稱 ( i , j ) (i, j) (i,j)是對兒好整數。求好整數的數量。

  • 條件 a k ∣ a i a_k \ | \ a_i ak???ai? a k ∣ a i a_k \ | \ a_i ak???ai?可以轉化為 a k ∣ g c d ( a i , a j ) a_k \ | \ gcd(a_i, a_j) ak???gcd(ai?,aj?)。由于值域僅有 1 0 6 10^6 106級別,我們可以預處理出 f ( x ) ( 1 ≤ x ≤ 1 0 6 ) f(x) \ (1 \leq x \leq 10^6) f(x)?(1x106) f ( x ) f(x) f(x)表示 g c d ( i , j ) = x gcd(i, j) = x gcd(i,j)=x好整數的個數。

    • y ∣ g c d ( a i , a j ) y\ | \ gcd(a_i, a_j) y??gcd(ai?,aj?),此時 a i a_i ai? a j a_j aj? y y y的倍數,故可以枚舉 y y y的倍數計算出數量 s u m sum sum。那么 y ∣ g c d ( a i , a j ) y \ | \ gcd(a_i,a_j) y??gcd(ai?,aj?) ( i , j ) (i, j) (i,j)的對數是 C s u m 2 = s u m × ( s u m ? 1 ) 2 C_{sum}^2 = \frac{sum \times (sum - 1)}{2} Csum2?=2sum×(sum?1)?。其中存在兩種情況 y = g c d ( a i , a j ) y = gcd(a_i, a_j) y=gcd(ai?,aj?) y < g c d ( a i , a j ) y < gcd(a_i, a_j) y<gcd(ai?,aj?),(也就是 g c d ( a i , a j ) gcd(a_i, a_j) gcd(ai?,aj?) y y y的大于 1 1 1倍的倍數)。所以 f ( x ) = s u m × ( s u m ? 1 ) 2 ? f ( 2 x ) ? f ( 3 x ) ? . . . f(x) = \frac{sum \times (sum - 1)}{2} - f(2x) - f(3x) -... f(x)=2sum×(sum?1)??f(2x)?f(3x)?...
    for (int i = n; i >= 1; i --) {int s = 0, t = 0;for (int j = i; j <= n; j += i) {s += cnt[j];t += f[j];}f[i] = s * (s - 1) / 2 - t;}
    
  • 在值域之中,我們將 a m ( 1 ≤ m ≤ n ) a_m(1 \leq m \leq n) am?(1mn)及其倍數篩掉,剩下的就是 f ( x ) f(x) f(x) x x x可以取的值。于是 a n s = ∑ i = 1 n f ( i ) ( 其中 i 未被篩掉 ) ans = \sum^{n}_{i = 1}f(i) \ (其中i未被篩掉) ans=i=1n?f(i)?(其中i未被篩掉)

#include <bits/stdc++.h>
using namespace std;using LL = long long;#define int LLvoid solve() {int n;cin >> n;vector<int> f(n + 1, 0);vector<int> cnt(n + 1, 0);for (int i = 0; i < n; i ++) {int x;cin >> x;cnt[x] ++;}for (int i = n; i >= 1; i --) {int s = 0, t = 0;for (int j = i; j <= n; j += i) {s += cnt[j];t += f[j];}f[i] = s * (s - 1) / 2 - t;}vector<int> vis(n + 1, false);for (int i = 1; i <= n; i ++) {if (cnt[i]) {for (int j = i; j <= n; j += i) {vis[j] = true;}}}int res = 0;for (int i = 1; i <= n; i ++) {if (vis[i] == false) {res += f[i];}}cout << res << endl;
}signed main() {ios::sync_with_stdio(false);cin.tie(nullptr);int t;cin >> t;while (t --) {solve();}return 0;
}

約數

約數個數

對于一個正整數 x x x,由于唯一分解定理, x = p 1 a 1 × p 2 a 2 × p 3 a 3 × p 4 a 4 . . . x = p_1^{a_1} \times p_2^{a_2} \times p_3^{a_3} \times p_4^{a_4}... x=p1a1??×p2a2??×p3a3??×p4a4??...

對于 x x x的每一個約數 y y y y y y都能寫成 y = p 1 b 1 × p 2 b 2 × p 3 b 3 × p 4 b 4 . . . ( 0 ≤ b 1 ≤ a 1 , 0 ≤ b 2 ≤ a 2 , 0 ≤ b 3 ≤ a 3 , 0 ≤ b 4 ≤ a 4 ) y = p_1^{b_1} \times p_2^{b_2} \times p_3^{b_3} \times p_4^{b_4}... \ (0 \leq b_1 \leq a_1,0 \leq b_2 \leq a_2, 0 \leq b_3\leq a_3,0 \leq b_4 \leq a_4) y=p1b1??×p2b2??×p3b3??×p4b4??...?(0b1?a1?,0b2?a2?,0b3?a3?,0b4?a4?)

所以約數個數為 ( a 1 + 1 ) × ( a 2 + 1 ) × ( a 3 + 1 ) × ( a 4 + 1 ) × . . . (a_1 + 1) \times (a_2 + 1) \times (a_3 + 1) \times (a_4 + 1) \times ... (a1?+1)×(a2?+1)×(a3?+1)×(a4?+1)×...

約數之和

約數之和 s u m = ( p 1 0 + p 1 1 + . . . + p 1 a 1 ) × ( p 2 0 + p 2 1 + . . . + p 2 a 2 ) × ( p 3 0 + p 3 1 + . . . + p 3 a 3 ) × ( p 4 0 + p 4 1 + . . . + p 4 a 4 ) × . . . sum = (p_1^0 + p_1^1 + ... + p_1^{a_1}) \times (p_2^0 + p_2^1 + ... + p_2^{a_2}) \times (p_3^0 + p_3^1 + ... + p_3 ^ {a_3}) \times (p_4^0 + p_4^1 + ... + p_4^{a_4}) \times ... sum=(p10?+p11?+...+p1a1??)×(p20?+p21?+...+p2a2??)×(p30?+p31?+...+p3a3??)×(p40?+p41?+...+p4a4??)×...

由分配律將上述括號拆開可得: x 1 + x 2 + x 3 + . . . + x_1 + x_2 + x_3 + ... + x1?+x2?+x3?+...+,其中每一項都是 x x x的約數

#include <bits/stdc++.h>
using namespace std;using LL = long long;const int mod = 1e9 + 7;int n;
map<int, int> cnt;int main() {ios::sync_with_stdio(false);cin.tie(nullptr);cin >> n;for (int i = 0; i < n; i ++) {int x;cin >> x;for (int j = 2; j <= x / j; j ++) {if (x % j != 0) continue;int t = 0;while (x % j == 0) {t ++;x /= j;}cnt[j] += t;}if (x > 1) cnt[x] ++;}   LL res = 1;for (auto& [u, v] : cnt) {LL t = 0;for (int j = 0; j <= v; j ++) {t = (t * u % mod + 1) % mod;}res = res * t % mod;}cout << res << endl;return 0;
}

組合數

C n m = C n ? 1 m ? 1 + C n ? 1 m C^{m}_{n} = C_{n - 1}^{m - 1} + C_{n - 1}^{m} Cnm?=Cn?1m?1?+Cn?1m?

可由此式子遞推計算組合數

void init() {for (int i = 0; i <= N - 1; i ++) {c[i][0] = 1;}for (int i = 1; i <= N - 1; i ++) {for (int j = 1; j <= N - 1; j ++) {c[i][j] = (c[i - 1][j] % mod + c[i - 1][j - 1] % mod) % mod;}}
}

C n m = A n m A m m = n ! ( n ? m ) ! m ! = n ! m ! ( n ? m ) ! C_n^m = \frac{A_n^m}{A_m^m} = \frac{\frac{n!}{(n - m)!}}{m!} = \frac{n!}{m!(n - m)!} Cnm?=Amm?Anm??=m!(n?m)!n!??=m!(n?m)!n!?

可以預處理出來 f a c t [ N ] fact[N] fact[N] i n f a c t [ N ] infact[N] infact[N]

C n m = f a c t [ N ] × i n f a c t [ m ] × i n f a c t [ n ? m ] C_n^m = fact[N] \times infact[m] \times infact[n - m] Cnm?=fact[N]×infact[m]×infact[n?m]

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
#define endl "\n"
typedef pair<int, int> pII;
const int p = 1e9 + 7;
const int N = 100010;
LL fact[N], infact[N];LL qmi(LL a, LL b, LL p) {LL res = 1;while (b) {if (b & 1) res = res * a % p;a = a * a % p;b >>= 1;}return res;
}LL inv(LL x) {return qmi(x, p - 2, p);}void init(int n) {fact[0] = 1;for (int i = 1; i <= n; i ++) fact[i] = fact[i - 1] * i % p;infact[n] = inv(fact[n]);for (int i = n - 1; i >= 0; i --) infact[i] = infact[i + 1] * (i + 1) % p;
}void solve() {int n, m; cin >> n >> m;cout << (fact[n] % p) * (infact[n - m] % p * infact[m] % p) % p << endl;
}int main() {ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);init(100005);int t; cin >> t;while (t --) {solve();}return 0;
}

盧卡斯定理

C n m = C n p m p × C n m o d p m m o d p C_n^m = C^{\frac{m}{p}}_{\frac{n}{p}} \times C^{m \ mod \ p}_{n \ mod \ p} Cnm?=Cpn?pm??×Cn?mod?pm?mod?p?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/900321.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/900321.shtml
英文地址,請注明出處:http://en.pswp.cn/news/900321.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

006貪心——算法備賽

跨步問題 跳躍游戲|| 問題描述 給定一個長度為 n 的 0 索引整數數組 nums。初始位置為 nums[0]。 每個元素 nums[i] 表示從索引 i 向后跳轉的最大長度。換句話說&#xff0c;如果你在 nums[i] 處&#xff0c;你可以跳轉到任意 nums[i j] 處: 0 < j < nums[i]i j &…

MySQL學習筆記(三)——圖形化界面工具DataGrip

目錄 1. 圖形化界面工具 2.下載 3. 安裝 3.1 安裝步驟 3.2 激活說明 4. 使用 4.1 漢化教程 4.2 使用 1. 圖形化界面工具 上述&#xff0c;我們已經講解了通過 DDL 語句&#xff0c;如何操作數據庫、操作表、操作表中的字段&#xff0c;而通過 DDL 語句執行在命令進行操…

編程題學習

acwing 826. 單鏈表 #include <iostream>using namespace std;const int N 100010;int idx, e[N], ne[N], head;void init() {head -1;idx 0; }void insert_head(int x) {e[idx] x;ne[idx] head;head idx ; }void delete_k_pos(int x, int k) {e[idx] x;ne[idx…

modelscope環境準備--裝conda、內網穿透、配置HuggingFace

1 準備anaconda #1、安裝包 wget https://repo.anaconda.com/archive/Anaconda3-2024.10-1-Linux-x86_64.sh#2、提高權限 chmod x Anaconda3-2024.10-1-Linux-x86_64.sh#3、執行安裝命令 ./Anaconda3-2024.10-1-Linux-x86_64.sh#4、一直按Enter健繼續 yes繼續 Enter#5、手動激…

算法題(117):字符串的展開

審題&#xff1a; 本題需要我們根據題目的要求將字符串進行擴展 思路&#xff1a; 方法一&#xff1a;模擬法 一般來說題目字數和要求很多的題就是模擬題&#xff0c;模擬題特別需要注意的就是細節&#xff0c;在編寫代碼之前一定要把細節想清楚&#xff0c;否則很容易出錯。 分…

15使用按鈕實現helloworld(2)

目錄 通過純代碼的方式實現的 按版 hello world 通過圖形化界面的方式&#xff0c;實現的 按鈕版 hello world 通過純代碼的方式實現的 按版 hello world 對于純代碼版本,按鈕對象是咱們自己 new 的 為了保證其他函數中能夠訪問到這個變量,就需要把按鈕對象 設定為 Widget 類…

Nacos 服務發現的核心模型有哪些?Service, Instance, Cluster 之間的關系是什么?

Nacos 服務發現的核心模型 Nacos 服務發現的核心數據模型主要圍繞以下幾個關鍵概念構建&#xff0c;它們共同構成了服務注冊與發現的基礎&#xff1a; Namespace (命名空間): 用途: 用于進行環境隔離。比如&#xff0c;你可以為開發環境 (dev)、測試環境 (test) 和生產環境 (p…

VMware 安裝 Ubuntu 全流程實戰指南:從零搭建到深度優化

在軟件開發、系統測試以及技術學習等諸多場景中&#xff0c;使用虛擬機安裝操作系統是一種靈活且高效的方式。Ubuntu 作為一款優秀的開源操作系統&#xff0c;在 VMware 虛擬機上的安裝與優化備受關注。接下來&#xff0c;將為大家帶來 VMware 安裝 Ubuntu 的全流程實戰指南&am…

探秘叁仟智盒設備:智慧城市的智能樞紐

在智慧城市建設的宏偉藍圖中&#xff0c;各類先進技術與設備層出不窮&#xff0c;叁仟智盒設備作為其中的關鍵一環&#xff0c;正悄然發揮著巨大作用&#xff0c;為城市的智能化轉型注入強大動力。 一、叁仟智盒設備概述 叁仟智盒設備是杭州叁仟智慧城市科技有限公司旗下的重…

晶晨S905L3S/S905L3SB_安卓9.0_10秒開機_通刷-線刷固件包

晶晨S905L3S&#xff0f;S905L3SB_安卓9.0_10秒開機_通刷-線刷固件包 線刷方法&#xff1a;&#xff08;新手參考借鑒一下&#xff09; 使用晶晨刷機工具USB_Burning_Tool進行刷機&#xff1b;請使用Amlogic USB Burning Tool v2.2.5或v2.2.7&#xff08;晶晨線刷燒錄工具v2.2…

VSCode中結合DeepSeek使用Cline插件的感受

前言 聽網上有傳言說AI智能插件Cline非常的好用&#xff0c;而且相對Cursor而言還是免費的&#xff0c;捆綁的大模型選擇也比較的廣泛。所以&#xff0c;特意安裝試用了一下。 我的采用IDE是VSCode&#xff0c;捆綁的大模型是最近比較火的DeepSeek。總體使用下來感覺非常的棒。…

藍橋云客--破譯密碼

5.破譯密碼【算法賽】 - 藍橋云課 問題描述 在近期舉辦的藍橋杯競賽中&#xff0c;誕生了一場激動人心的雙人破譯挑戰。比賽的主辦方準備了N塊神秘的密碼芯片&#xff0c;參賽隊伍需要在這場智力競賽中展示團隊合作的默契與效率。每個隊伍需選出一位破譯者與一位傳輸者&#…

中國移動啟動數字鄉村“五新升級”:年底前,行政村5G覆蓋達95%

大灣區經濟網品牌觀察報道&#xff0c;近日&#xff0c;在國家全面推進鄉村振興的戰略背景下&#xff0c;中國移動近日發布數字鄉村升級行動計劃&#xff0c;以“AI大模型數智化平臺”為核心引擎&#xff0c;圍繞“五新升級”構建“兩個新型”信息服務體系。 一、數字基建筑基&…

智慧節能雙突破 強力巨彩谷亞VK系列刷新LED屏使用體驗

當前全球節能減排趨勢明顯&#xff0c;LED節能屏作為顯示技術的佼佼者&#xff0c;正逐漸成為市場的新寵。強力巨彩谷亞萬境VK系列節能智慧屏憑借三重技術保障、四大智能設計以及大師臻彩畫質&#xff0c;在實現節能效果的同時&#xff0c;更在智慧顯示領域樹立新的標桿。   …

Apache 配置負載均衡詳解(含配置示例)

Apache 是互聯網上最受歡迎的 Web 服務器之一。除了基本的網頁服務&#xff0c;它還能通過模塊擴展出豐富的功能。其中一個重要用途就是將 Apache 配置成負載均衡器&#xff0c;用于在多個后端服務器之間分配流量&#xff0c;提升網站的性能和穩定性。Google Gemini中國版調用G…

GESP:2025-3月等級8-T1-上學

時間限制 : 1 秒 內存限制 : 128 MB C 城可以視為由 n個結點與 m條邊組成的無向圖。這些結點依次以1,2,....n標號&#xff0c;邊依次以 1,2...m標號。第i條邊&#xff08;1<i<m &#xff09;連接編號為ui 與vi的結點&#xff0c;長度為li米。 小 A 的學校坐落在 C 城中…

Nginx介紹及使用

1.Nginx介紹 Nginx是一款開源的、高性能的HTTP和反向代理服務器 1.正向代理和反向代理 正向代理&#xff08;代理客戶端&#xff09;是一種位于客戶端和目標服務器之間的中間服務器。客戶端通過正向代理服務器向目標服務器發送請求&#xff0c;代理服務器將請求轉發給目標服…

復古未來主義屏幕輝光像素化顯示器反烏托邦效果PS(PSD)設計模板樣機 Analog Retro-Futuristic Monitor Effect

這款模擬復古未來主義顯示器效果直接取材于 90 年代賽博朋克電影中的黑客巢穴&#xff0c;將粗糙的屏幕輝光和像素化的魅力強勢回歸。它精準地模仿了老式陰極射線管顯示器&#xff0c;能將任何圖像變成故障頻出的監控畫面或高風險的指揮中心用戶界面。和……在一起 2 個完全可編…

[巴黎高師課程] 同步反應式系統(2024-2025)第三課 - Kind 2: 基于SMT的Lustre模型檢查器

在2024-2025學期的巴黎高師同步反應式系統(2024-2025)第三課中&#xff0c;詳細討論了基于SMT的Lustre模型檢查器Kind 2的工作。本文將提供對Kind 2的介紹。對課程的詳細內容&#xff0c;可參考同步反應式系統 簡介 本節課討論了基于SMT&#xff08;Satisfiability Modulo The…

軌道交通裝備三維檢測與輕量化設計

地鐵車身與車燈部件作為軌道交通裝備的核心組成部分&#xff0c;其制造精度和性能要求極高。由于它們體積龐大、曲面復雜&#xff0c;傳統檢測方法在面對這些大型、復雜部件時&#xff0c;不僅耗時費力&#xff0c;而且難以實現全面、精確的測量&#xff0c;難以滿足高效、準確…