1. 程式人生 > 實用技巧 >要命的逆元

要命的逆元

Day 2 基礎數論演算法

from hzwer
by Zxsure

基礎概念:

假設 m 和 n 是整數,且 m 不是 0,則 m 整除 n 指的是 n 是 m 的倍
數,即存在整數 k,使得 n = mk

\[{m \| n \longrightarrow n = km} \]

如果 m 整除 a - b,我們就說 a 與 b 模 m 同餘並記

\[\ a\ ≡ \ b(\mod \ m) \]


例題:

  1. 證明:如果一個數每一位加起來可以被 3 整除,那這個數就可以被 3
    整除?

\[\begin{align} abcd\ & =\ 1000d\ +\ 100c\ +\ 10b\ +\ a \\ & ≡a\ +b\ +c\ +d\ (mod\ 3) \end{align} \]

素數

時間複雜度

\[{O\sqrt n} \]

for(2~(sqrt)n)
check(i % m == 0)

素數篩法

在數列中篩去 2 ,3 ,5,7,8,9的倍數;

時間複雜度:

\[{n\ log\ log n} \]


例題

  1. 分解質因數

  2. 假設素數是有限的,假設素數只有有限的n個,最大的一個素數是p。

    \[{q_{max}\ = (2×3×4\cdots×p)+1} \]

  3. 不能被所有的素數整除就找到更大的素數。


素數的唯一分解

若整數 N≥2,那麼 N 一定可以唯一地表示為若干素數的乘積。
形如

  • \({N = p_1^r ×p_2^r× …×p_k^r(p_i 為素數 , r_i ≥ 0)}\)

最小公倍數

\[gcd(a,b)=1(a,b\ 互質) \]

\[gcd(a,b) = gcd(b ,a\ mod\ b) \]

return b = 0 ? a : gcd(b,a % b)

歐幾里得演算法

\({gcd(a,b)=gcd(b, a\ mod \ b)}\)

• 設 g = gcd(a, b),r = a mod b,我們可以知道 a = kg + r

• 再根據 g 的最大公因數的性質(也就是同時整除a和b)就可以知道 g 也整除 r。

• 同樣的,我們也可以證明,g 是同時整除 b 和 r 的最大的整數,這樣,這個等式就成立了。

逆元

\[X*X^{-1}=1(mod\ p) \]

條件 :解決同餘意義下,無法進行除法的問題

推理:

\[\left\{ \begin{array}{c} {(a/b)\ mod\ p\not= \frac{a\ mod\ p}{b\ mod\ p}}\\ {(a/b)\ mod\ p\ = (a\ mod\ p)*(b^{-1}\ mod \ p)} \end{array} \right. \]


推理過程

  • 我們有: inv(x)⋅x≡1 (mod p), 又據費馬小定理:x^(p-1) ≡ 1 (mod p)

  • 故有:inv(x)⋅x ≡ x^(p-1) (mod p) ,兩邊同時除以 x 有:

  • inv(x) ≡ x^(p-2) (mod p) ,這就是模質數意義下的逆元求法。

  • \(inv\) 表示逆元

結論

\[a^{-1}=a^{p-2} \]

快速冪

  1. 求快速冪 \(a^b\)

  2. 預處理 \({a^1\ a^2\ a^3\ \cdots\ a^{2n} }\),對b進行二進位制拆分

  3. 如:\({a^{21}=a^{16}*a^{4}*a^{1}}\)


練習題

CF1209A.Paint the Numbers (900)

題面:

  • 給 n 個數 a1 ~ an。要求你把它們分成 k 組,使得每⼀組中的數,都能被這一組最小值整除。問 k 最小是多少?

  • n <= 100, ai <= 10000

思路 :

  1. 將序列排序,從頭往後一次考慮最小數

  2. 貪心+模擬

  3. 以當前最小數去找到與其相關的倍陣列成一組(貪)

  4. 貪⼼篩法,每次取沒被篩掉的最小元素,篩掉它的倍數(PPT)

Code :


CF486A.Calculating Function (1100)

題面 :

  • 計算函式 f(n) = -1 + 2 - 3 + .. + ( - 1)^n * n

  • n <= 10^15

思路 :

  1. n 為奇數,答案是 -(n+1)/2

  2. n 為偶數,答案是 n / 2


CF492B.Vanya and Lanterns (1200)

題面 :

  • 一個長為 L 的街道(左端點是 0,右端點是 L)上有 n 個相同的燈,第 i 個燈放置的位置是 ai

  • 問燈的半徑至少要是多少,才能使得整個街道都有燈光。

  • n <= 1000, L <= 10^9

思路:

  1. 暴力找到燈之間的距離一半最大值

  2. 再比較兩邊界的的燈的距離。

CF570B. Simple Game (1300)

題面:

  • 給 n,m,求⼀個數 a (1 ≤ a ≤ n),使得當 c 在 1 到 n 的整數中隨機取值時, |c − a| < |c − m| 成立的概率最大。

  • n, m <= 10^9, m <= n

思路:

  1. 分 2m ≤ n 和 2m > n 討論

CF546B.Soldier and Badges (1300)

題面 :

  • 給 n 個數,每次操作可以將一個數 +1,要使這 n 個數都不相同, 求至少要加多少?

  • n <= 3000

思路:

  1. 排序,挨個+1

401C.Team(1400)

題面:

  • 構造一個 01 序列,包含 n 個 0,m 個 1

  • 要求不存在連續 2 個 0,或 3 個 1

  • 無解輸出 -1

  • 1 ≤ n, m ≤ 10^6

思路:

  1. 判斷無解的情況下。

  2. 011和01進行構造

Code

/*
 	2020/10/3 20:59
 	CF401C Team
	by BZQ
*/
#include<iostream>
using namespace std;
int n,m;
int main(){
	cin >> n;
	cin >> m;
	if(m > n*2 + 2 || n > m+1) cout << -1;//判斷無解的情況 
	else
	{
		if(m > n*2){         //此處將 m >= n 的情況和 m > 2n 的情況做個合併。                
			for(int i = 1;i <= m - n*2; i++)//先對 m > 2n 進行預處理,之後操作一樣。
				cout << "1";
			m = 2 * n; //注意:在做完預處理後,現在的序列就相當於是一個滿011和01的序列,所以更新m; 				
		}
	    if(m >= n){
			for(int i = 1;i <= m - n; i++) // 先貪大後貪小 
		 		cout << "011";
			for(int i = 1;i <= 2*n-m; i++)
		 		cout << "01";
		}
 		if(n > m){
			cout << "0"; // 回覆思路 1 中的問題:以為無解的邊界為 n > m+1 故要想此時的 n > m 成立,當且僅當 n = m + 1; 
			for(int i = 1;i <= m;i++)
			 	cout << "10";
		}
	}
	return 0;
} //感謝觀看,

413C.Jeopardy!(1400)


題面:

  • 給 n 個關卡,每個關卡得分為 ai,有 m 次機會可以選擇一個關卡通過後不得分,而將現有得分翻倍

  • 你可以安排關卡的通過順序和策略,求最大得分

  • 1 ≤ n, m ≤ 100

思路:

  1. 將可以翻倍關卡放在後頭,且按從一到n排序,依次貪心

POJ2689. Prime Distance


題面 :

  • 給定兩個整數 L, R (1 ≤ L ≤ R ≤ 2^31, R-L ≤ 10^6),

  • 求閉區間[L, R] 中相鄰兩個素數的差最大是多少?

思路:

  1. 預處理\({\sqrt{2^{31}}}\);

  2. 暴力判斷

  3. 使用篩法求出 [2,√R] 之間的所有素數,對於每個素數 p ,把[L,R] 中能被 p 整除的數標記,即標記 i × p(⌈L/p⌉ ≤ i ≤ ⌊R/p⌋)為合數。

  4. 將篩出的素數進行相鄰兩兩比較,找出差最大的即可


235A.LCM Challenge (1600)


題面:

  • 在小於n 的數中找三個數 a, b, c

  • 最大化 lcm(a, b, c)

  • n <= 10^6

思路:

  1. 在接近 n 的數內找三個兩兩互質的,小範圍暴力

NOIP2014. 解方程

題面:

已知多項式方程:

  • a_0+a_1x+a_2x^2+\cdots+a_nx^n=0a0+a1x+a2x2+⋯+anx**n=0

  • 求這個方程在 [1,m][1,m] 內的整數解(nn 和 mm 均為正整數)。

思路:

  1. 暴力驗證[1,m]內的整數?係數太大,取模!

  2. 方程的解不會超過n個

  3. 如果\(x=x_0\)的時候,在對$p $ 取模後方程不成立,那麼原方程必然不成立

  4. 用比較小的質數驗證一個,先排除大部分

以上思路來源PPT,本人無思路,因為不會

作者 @Zxsure,轉載請宣告出處