從頭整理一下

大部分是照着書和課件來的,主要爲了方便複習算法

貪心

1.選擇不相交區間問題函數

按照結束時間點排序ui

 

2.區間選點atom

考慮一個區間的後部最優,從後向前選spa

 

3.區間覆蓋code

去除無用點以後按照左端點排序,每次選擇未處理區間內的第一個點進行詢問blog

 

4.流水做業調度排序

(Johnson)設mi=min{ai,bi}記錄轉移的方向,排序以後依次判斷,原來是a加在左邊是b加在右邊get

 

5.帶限期和罰款的單位時間任務調度數學

貪心的前提是必定要是單位時間,儘可能先完成罰款比較大的工做,排序後找最晚時間去安排上,不然放在最後的空位上

 

數學

在oi上基本大部分的數學知識都體如今數論的有關內容上

會推數學式子纔是數論題的關鍵,數學纔是數論題的基礎與核心

GCD:
原理: (a,b) = (b,a%b)

Code:

int gcd(int a,int b) { if(a % b == 0) return a; return gcd(b,a % b); }

Exgcd:

目的是求: ax + by = gcd(a,b)的一組解(x,y)

同時返回的是d = gcd(a,b)

Code:

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

 

Miller_Rabin

這個算法是主要用來判斷某一個數是否是質數的算法

可是請注意這個算法具備隨機性,並且是單點判斷,不適用於區間的素數篩選

這個算法的證實(手寫):

 

Code:

int gg[8] = {2,3,5,7,13,29,37,89}; Miller_Rabin(int a,int n) { int d = n - 1; int r = 0; while(d % 2 == 0) { d /= 2; r++; } int x = kuaisumi(a,d,n); if(x == 1) return true; for(int i=0;i<r;i++) { if(x == n - 1) return true; x = (long long)x * x % n; } return false; } bool is_prime(int n) { if(n <= 1) return false; for(int a=0;a<8;a++) if(n == gg[a]) return true; for(int a=0;a<8;a++) if(!Miller_Rabin(gg[a],n)) return false; return true; }

 

線性篩:

線性篩的算法有不少種,可是本文這裏爲了簡便起見

只介紹歐拉篩了,同時由於歐拉篩能夠預處理莫比烏斯函數和歐拉函數等數論函數

還能夠得出每個合數的最小非1因子

好處多多a

Code:

memset(not_prime,0,sizeof(not_prime)); for(int i=2;i<=n;i++) { if(!not_prime[i]) { prime[++prime_cnt] = i; phi[i] = i - 1; mu[i] = -1; } for(int j=1;j<=prime_cnt;j++) { int x = i * prime[j]; if(x > n) break; not_prime[x] = true; phi[x] = phi[i] * phi[prime[j]]; mu[x] = mu[i] * mu[prime[j]]; if(i % prime[j] == 0) { phi[x] = phi[i] * prime[j]; mu[x] = 0; break; } } }

 

快速冪:

這個的原理就是在實現的時候將每個數將其"拆分"

從而咱們能夠用倍數來×代替了×多少次

Code:

int quickpow(int a,int b,int p) { int res = 1; while(b) { if(b & 1) res = res * a % p; a = a * a % p; b >>= 1; } return res; }

 

 

中國剩餘定理:

定理內容:

中國剩餘定理的形式是這樣的:

存在一個這樣的式子:(中國剩餘定理的限制條件:m1,m2,m3...mn這些數是互質的)

 而後咱們的任務是求最小的整數x使得非負整數x知足以上條件

咱們設定一個 M = mi (即M爲全部m的最小公倍數)

方程 M / mi * ti ≡ 1 (mod mi) 中 ti 爲其最小非負整數解 (這裏能夠用exgcd來實現求解)

那麼有一個解爲 x = ∑ ai * M / mi * ti

通解爲: x + i * M

特別地,算法的非負整數解爲 (x % M + M) % M (將x移到[0,M]這個區間內)

算法證實:

由於M / mi 是除了mi以外的全部數的倍數

那麼對於任意的k ≠ i 都有 ai * M / mi * ti ≡ 0 (mod mk)

又有M / mi * ti ≡ 1 (mod mi)

將兩邊同時乘ai得 ai * M / mi * ti ≡ ai (mod mi)

最後咱們帶入x = ∑ ai * M / mi * ti

從而原方程組成立

Code:

void exgcd(int a,int b,int &x,int &y) { if(b == 0) { x = 1; y = 0; return ; } exgcd(b,a % b,x,y); int t = x; x = y; y = t - a / b * y; } int crt() { int ans = 0; int M = 1; int x,y; for(int i=1;i<=k;i++) M *= b[i]; for(int i=1;i<=k;i++) { int t = M / b[i]; exgcd(t,b[i],x,y); x = (x % b[i] + b[i]) % b[i]; ans = (ans + t * x * a[i]) % M; } return (ans + M) % M; }

 

拓展中國剩餘定理

 

這個與中國剩餘定理不一樣的地方就在於這裏的mi不必定兩兩互質了

解法:

咱們假設已經求解出前k - 1個同餘方程組的解爲x

而且有M=∏(i1,k1​)mi

那麼前k個方程組的通解爲 x + i * M(i ∈ Z)

對於咱們即將插入第k個方程後造成的k個方程造成的方程組

咱們就是要求一個正整數t,使得

x + t * M ≡ ak (mod mk)

咱們針對於這一個式子轉化一下就能夠獲得:

t * M ≡ ak - x (mod mk)

咱們能夠利用exgcd求解t

若這一個方程組無解t那麼這整個方程組也就是無解的(顯然,咱們沒法找到一個x使得x知足以上的方程成立條件)

如有,則前k個同餘式構成的方程組的一個解爲:
xk = x + t * M

因此咱們整個算法的核心思路就是咱們求解k次exgcd對於方程進行了k - 1次的展開

Code:

int exgcd(int a,int b,int &x,int &y) { if(b == 0) { x = 1; y = 0; return a; } int d = exgcd(b,a % b,x,y); int t = x; x = y; y = t - a / b * y; return d; } int excrt() { int x,y,k; int M = b[1]; int ans = a[1]; for(int i=2;i<=n;i++) { int aa = M; int bb = b[i]; int c = (a[i] - ans % bb + bb) % bb; // x + t * M ≡ ak (mod mk) int d = exgcd(aa,bb,x,y); //求一組解 int m = bb / d; if(c % d != 0) //若無解就直接返回 return -1; x = x * (c / d) % m; ans += x * M; M *= m; //要將這個mi加入到M裏面 ans = (ans % M + M) % M; // xk = x + t * M  } return (ans % M + M) % M; //返回值 }

放兩道模板題:

中國剩餘定理

拓展中國剩餘定理

 

BSGS(Baby Step Giant Step)算法

它還能夠找循環節!

其實它還叫(拔山蓋世算法qwq)

這個算法的問題主要就是求解已知A, B, C,求X使得A^x = B (mod C)

而後這個算法的核心思路就是分塊枚舉(也就是比較好看的暴力)

咱們須要完整地算出第一行的全部數的值

在第二行及之後咱們即可以對於每一行都進行二分運算(這裏咱們對於它進行排序便於二分)

咱們判斷在每一行的值有沒有等於的地方

最後就能夠在有這個函數值的一行進行算找那一個特殊值就行了(對於取模運算能夠在快速冪的時候注意一下)

分塊的大小是sqrt() * sqrt()的

而接下來將給出爲何是sqrt()的證實

 

由於 x = i*m-j , 因此x 的最大值不會超過p

 

由費馬小定理知: 當p爲質數且 (a,p1 時 ap-1 ≡ (mod p)

 

因此 當 x = p-1 時 ap-1 ≡ 1 會從新開始循環 因此 x 最大不會超過 p-1

 

因此:若是枚舉 x 的話枚舉到 p 便可。

 

因此使 imj<=p , 即 m=⌈√p⌉ , i,j 最大值也爲m。

Code:

int size; bool erfen(int x) { int l = 0; int r = size; while(l + 1 != r) { int m = (l + r) >> 1; if(z[m] >= x) r = m; else l = m; } return z[r] == x; } int BSGS(int a,int b,int p) { size = sqrt(p); int nowv = 1; for(int i=1;i<=size;i++) { nowv = (long long) nowv * a % p; z[i] = nowv; if(z[i] == b) return i; } sort(z + 1,z + size + 1); for(int i=2;(i - 1) * size + 1<=p;i++) { int y = (long long)b * kuaisumi(kuaisumi(a,size * (i - 1),p),p - 2,p); if(erfen(y)) { for(int j=(i - 1) * size + 1;j<=i*size;j++) if(kuaisumi(a,j,p) == b) return j; } } return -1; }
相關文章
相關標籤/搜索