# 從頭整理一下

## 貪心

1.選擇不相交區間問題

2.區間選點

3.區間覆蓋

4.流水作業調度

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

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

## 數學

GCD：

Code:

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

Exgcd:

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;
}

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;
}

然後我們的任務是求最小的整數x使得非負整數x滿足以上條件

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;
}

x + t * M ≡ ak (mod mk)

t * M ≡ ak - x (mod mk)

xk = x + t * M

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)算法

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;
}