ACM演算法模板--BY Focus
阿新 • • 發佈:2018-12-11
1.數學
1.1素數
1.1.1素數篩法(尤拉篩法,判斷<maxn的數是否是素數及求取<maxn的素數)
/* *notprime是一張表,false表示是素數,true表示不是素數 *prime是素數表,儲存小於maxn的全部素數。 */ const int maxn = 10500000; int prime[maxn]; bool notprime[maxn]; int Euler(int _n) //尤拉篩法求素數,時間複雜度為O(n)。 { int cnt = 0; memset(notprime, 0, sizeof notprime); memset(prime, 0, sizeof prime); for (int i = 2; i <= _n; i++) { if(!notprime[i]) prime[cnt++] = i; for (int j = 0; j < cnt && i*prime[j] <= _n; j++) { notprime[i*prime[j]] = true; if (i % prime[j] == 0) break; } } return cnt; }
1.1.2素數篩法(埃氏篩法,判斷<maxn的數是否是素數及求取<maxn的素數)
/* *notprime是一張表,false表示是素數,true表示不是素數 *prime是素數表,儲存小於maxn的全部素數。 */ const int maxn = 10500000; int prime[maxn]; bool notprime[maxn]; int Eratosthenes(int _n) //埃拉託斯特尼篩法,時間複雜度為O(nloglogn). { int cnt = 0; memset(notprime, 0, sizeof notprime); memset(prime, 0, sizeof prime); for(int i = 2; i <= _n; i++) { if(!notprime[i]) { prime[cnt++] = i; for (int j = i+i; j <= _n; j += i) { notprime[j] = true; } } } return cnt; }
1.2最大公約數
int gcd(int big, int small)
{
if (small > big) swap(big, small);
int temp;
while (small != 0){ // 輾轉相除法
if (small > big) swap(big, small);
temp = big % small;
big = small;
small = temp;
}
return big;
}
1.3快速冪
1.3.1普通快速冪
int power(long long a, int n) { long long ans = 1; while(n > 0) { if(n&1) { ans *= a; ans %= mod; } a *= a%mod; a %= mod; n /= 2; } return ans%mod; }
1.3.2矩陣快速冪
書上
2.圖論
2.1最短路
2.1.1Dijkstra單源最短路
權值非負
int n, m, s, t;
int len;
struct road
{
int u, v, cost;
int next;
};
struct node
{
int v;
int len;
int cost;
node(int v, int l, int c):v(v),len(l),cost(c){}
friend bool operator <(node a, node b)
{
return a.cost>b.cost;
}
};
road G[maxn*5];
int head[maxn];
int dist[maxn];
bool vis[maxn];
void addroad(int u, int v, int cost)//加邊
{
G[len].u = u;
G[len].v = v;
G[len].cost = cost;
G[len].next = head[u];
head[u] = len++;
}
void dij()
{
fill(dist, dist+n+1, INF);
dist[1] = 0;
priority_queue<node> pque;
pque.push(node(1,0));
while(pque.size())
{
node p = pque.top(); pque.pop();
int v = p.v;
if(dist[v] < p.cost) continue;
for(int i = head[v]; i!=-1; i = G[i].next)
{
road e = G[i];
if(dist[e.v] > min(dist[e.v],max(dist[e.u], e.cost)))
{
dist[e.v] = min(dist[e.v],max(dist[e.u], e.cost));
pque.push(node(e.v, dist[e.v] ) );
}
}
}
}
2.1.2Bellman—Ford判環
int n, m, s, t;
int len;
struct road
{
int u, v, cost;
int next;
};
struct node
{
int v;
int len;
int cost;
node(int v, int l, int c):v(v),len(l),cost(c){}
friend bool operator <(node a, node b)
{
return a.cost>b.cost;
}
};
road G[maxn*5];
int head[maxn];
int dist[maxn];
bool vis[maxn];
void addroad(int u, int v, int cost)
{
G[len].u = u;
G[len].v = v;
G[len].cost = cost;
G[len].next = head[u];
head[u] = len++;
}
int bellman_ford()
{
int res;
fill(dist, dist+n+1, INF);
dist[1] = 0;
for(int i = 0; i < n; i++)
{
for(int k = 0; k < len; k++)
{
road e = G[k];
if(dist[e.v] > dist[e.u] + e.cost)
{
dist[e.v] = dist[e.u] + e.cost;
if(i == n-1)
{
return 0;
}
}
}
}
return 1;
}
2.1.3Floyd多源最短路
int G[maxn][maxn];//儲存e(i,j)的權值,不存在邊時設為INF,其中G[i][i]==0
void floyd()
{
for(int k = 0; k <= mx; k++)
{
for(int i = 0; i <= mx; i++)
{
for(int j = 0; j <= mx; j++)
{
G[i][j] = min(G[i][j], G[i][k] + G[k][j]);
}
}
}
}
2.1.4次短路演算法
int n, m, s, t;
int len;
struct road
{
int u, v;
int next;
int cost;
};
struct node
{
int v;
int cost;
node(int v, int c):v(v),cost(c){}
friend bool operator <(node a, node b)
{
return a.cost>b.cost;
}
};
road G[200500];
int head[maxn];
int dist[maxn];
int dist2[maxn];
void dij()
{
fill(dist2, dist2+n+1,INF);
fill(dist, dist+n+1,INF);
dist[1] = 0;
priority_queue<node> pque;
pque.push(node(1, 0));
while(pque.size())
{
node p = pque.top();pque.pop();
int v = p.v;
//if(dist2[v] < p.cost) continue;
for(int i = head[v]; i != -1; i=G[i].next)
{
road e = G[i];
int d = p.cost + e.cost;
if(dist[e.v] > d)
{
swap(dist[e.v], d);
pque.push(node(e.v, dist[e.v]));
}
if(dist2[e.v] > d && d > dist[e.v])
{
dist2[e.v] = d;
pque.push(node(e.v, dist2[e.v]));
}
}
}
}
2.1.5雙權值求花費
/*
*注意:在本模板中 len表示路長,cost表示花費。
*/
int n, m, s, t;
int len;
struct road
{
int u, v, len, cost;
int next;
};
struct node
{
int v;
int len;
int cost;
node(int v, int l, int c):v(v),len(l),cost(c){}
friend bool operator <(node a, node b)
{
if(a.len == b.len)
return a.cost>b.cost;
return a.len>b.len;
}
};
road G[maxn*5];
int head[maxn];
int mx = -INF;
int dist[maxn];
int cost[maxn];
int path[maxn];
void addroad(int u, int v, int l, int cost)
{
G[len].u = u;
G[len].v = v;
G[len].len = l;
G[len].cost = cost;
G[len].next = head[u];
head[u] = len++;
}
int dij()
{
int res = 0;
fill(dist, dist+n+1, INF);
fill(path, path+n+1, -1);
fill(cost, cost+n+1, 0);
dist[1] = 0;
priority_queue<node> pque;
pque.push(node(1, 0, 0));
while(pque.size())
{
node p = pque.top(); pque.pop();
int v = p.v;
if(dist[v] < p.len) continue;
for(int i = head[v]; i != -1; i = G[i].next)
{
road e = G[i];
if(dist[e.v] > dist[e.u] + e.len)
{
dist[e.v] = dist[e.u] + e.len;
cost[e.v] = cost[e.u] + e.cost;
path[e.v] = i;
pque.push(node(e.v, dist[e.v], cost[e.v]));
}
else if(dist[e.v] == dist[e.u] + e.len)
{
if(path[e.v] != -1 && G[path[e.v]].cost > e.cost)
{
path[e.v] = i;
pque.push(node(e.v, dist[e.v], cost[e.v]));
}
}
}
}
for(int i = 1; i <= n; i++)
{
if(path[i]!=-1)
{
res += G[path[i]].cost;
}
}
return res;
}
2.2最小(大)生成樹
2.2.1Prim演算法
int n, m, s, t;
int road[maxn][maxn];//儲存e(i,j)的權值,不存的邊設為INF
bool vis[maxn];//標記是否屬於集合X
int dist[maxn];//從集合X出發到每個頂點最小距離
int prim()
{
memset(vis, 0, sizeof vis);
fill(dist, dist+maxn, INF);
dist[1] = 0;
int res = 0;
while(1)
{
int v = -1;
//從不屬於X的定點中取出從距X最近的定點
for(int i = 1; i <= n; i++)
{
if(!vis[i] &&(v==-1|| dist[i] < dist[v])) v = i;
}
if(v == -1) break;
vis[v] = true;//把頂點v加入X
res += dist[v];//更新結果
for(int i = 1; i <= n; i++)
{
dist[i] = min(dist[i], road[v][i]);//更新dist陣列
}
}
return res;
}
2.2.2Kruskal演算法
int n, m, s, t;
int len;
struct road
{
int u, v, cost;
};
road G[maxn*5];
int par[maxn<<1];
void init()
{
for(int i = 0; i < maxn<<1; i++) par[i] = i;
}
int Find(int x)
{
return par[x]==x? x : par[x] = Find(par[x]);
}
bool same(int x, int y)
{
int fx = Find(x), fy = Find(y);
if(fx == fy)return true;
else return false;
}
void unite(int x, int y)
{
int fx = Find(x), fy = Find(y);
if(fx == fy) return;
else{
par[fx] = fy;
return;
}
}
bool cmp(road a, road b)
{
return a.cost>b.cost;
}
int kruskal()
{
sort(G, G+len, cmp);
init();
int res = 0;
for(int i = 0; i < len; i++)
{
road e = G[i];
if(!same(e.u, e.v))
{
unite(e.u, e.v);
res+=e.cost;
}
}
return res;
}
2.3強連通分量
2.3.1Tarjan演算法
int n, m;
struct edge
{
int u, v;
int next;
};
edge G[maxn<<3];
int h[maxn];
int dfn[maxn];
int low[maxn];
int color[maxn];
bool vis[maxn];
int tot, len, out, sum;
stack<int> sta;
void init()
{
fill(h, h+maxn, -1);
fill(dfn, dfn+maxn, 0);
fill(vis, vis+maxn, 0);
fill(isout, isout+maxn, 0);
fill(color, color+maxn, 0);
tot = 0;
len = 0;
sum = 0;
out = 0;
}
void tarjan(int u)
{
dfn[u] = low[u] = ++tot;
vis[u] = true;
sta.push(u);
for(int i = h[u]; ~i; i = G[i].next)
{
edge e = G[i];
if(!dfn[e.v])
{
tarjan(e.v);
low[u] = min(low[u], low[e.v]);
}
else if(vis[e.v])
{
low[u] = min(low[u], dfn[e.v]);
}
}
if(dfn[u] == low[u])
{
int x;
++sum;
do
{
x = sta.top(); sta.pop();
vis[x] = false;
color[x] = sum;
}
while(x != u);
}
}
2.3.2 Kosaraju演算法(解決2-SAT問題)
int n, m;
vector<int> G[maxn];
vector<int> rG[maxn];
vector<int> vs;
bool used[maxn];
int cmp[maxn];
int s[maxn], t[maxn], d[maxn];
void add_edge(int from, int to)
{
G[from].pb(to);
rG[to].pb(from);
}
void dfs(int v)
{
used[v] = true;
for(int i = 0; i < G[v].size(); i++)
{
if(!used[G[v][i]])
dfs(G[v][i]);
}
vs.pb(v);
}
void rdfs(int v, int k)
{
used[v] = true;
cmp[v] = k;
for(int i = 0; i < rG[v].size(); i++)
{
if(!used[rG[v][i]])
rdfs(rG[v][i], k);
}
}
int ssc()
{
memset(used, 0, sizeof used);
for(int i = 0; i < n<<1; i++)
{
if(!used[i])
dfs(i);
}
memset(used, 0, sizeof used);
int k = 0;
for(int i = vs.size()-1; i >= 0; i--)
{
if(!used[vs[i]])
rdfs(vs[i], k++);
}
return k;
}
/*
*如果需要輸出結果,變數i為真滿足的條件為cmp[i]>cmp[i+n],否則i為假
*/
3.資料結構
3.1線段樹
3.1.1單點更新的線段樹
int n, m, t, _n;
int dat[maxn<<2];
void build(int root, int left, int right)
{
if(left == right)
{
dat[root] = 1;
return;
}
int mid, rt;
mid = (left+right)>>1;
rt = root<<1;
build(rt, left, mid);
build(rt|1, mid+1, right);
dat[root] = dat[rt] + dat[rt|1];
}
void Update(int pos, int val, int root, int left, int right)
{
if(left==right)
{
dat[root] = val;
return;
}
int m=(left+right)>>1;
if(pos <= m) Update(pos, val, root<<1, left, m);
else Update(pos, val, root<<1|1, m+1, right);
dat[root] = dat[root<<1] + dat[root<<1|1];
}
int query(int qleft, int qright, int root, int left, int right)
{
if(qleft<=left && right<=qright)
{
return dat[root];
}
int m = (left+right)>>1;
int ans = 0;
if(qleft <= m ) ans += query(qleft, qright, root<<1, left, m);
if(qright > m) ans += query(qleft, qright, root<<1|1, m+1, right);
return ans;
}
3.1.2區間更新的線段樹
int n, m, t, _n;
struct node
{
long long num;
long long lazy;
};
node dat[maxn<<2];
long long arr[maxn];
void build(int k, int l, int r)
{
if(l==r)
{
dat[k].num = arr[l];
dat[k].lazy = 0;
return;
}
build(k<<1, l, (l+r)/2);
build(k<<1|1, (l+r)/2+1, r);
dat[k].num = dat[k<<1].num + dat[k<<1|1].num;
}
void update(int a, int b, long long val, int k, int l, int r)//區間加減
{
if(r<a || b<l) return;
if(a<=l && r<=b)
{
dat[k].lazy += val;
dat[k].num += (val*(r-l+1));
return;
}
if(dat[k].lazy)
{
dat[k<<1].num += ((l+r)/2-l+1)*dat[k].lazy;
dat[k<<1].lazy += dat[k].lazy;
dat[k<<1|1].num += (r-(l+r)/2)*dat[k].lazy;
dat[k<<1|1].lazy += dat[k].lazy;
dat[k].lazy = 0;
}
update(a,b,val,k<<1,l,(l+r)/2);
update(a,b,val,k<<1|1,(l+r)/2+1,r);
dat[k].num = dat[k<<1].num + dat[k<<1|1].num;
}
long long query(int a, int b, int k, int l, int r)
{
if(a<=l && r<=b)
return dat[k].num;
if(dat[k].lazy)
{
dat[k<<1].num += ((l+r)/2-l+1)*dat[k].lazy;
dat[k<<1].lazy += dat[k].lazy;
dat[k<<1|1].num += (r-(l+r)/2)*dat[k].lazy;
dat[k<<1|1].lazy += dat[k].lazy;
dat[k].lazy = 0;
}
int m = (l+r)/2;
long long ans = 0;
if(a<=m) ans+=query(a,b,k<<1,l,m);
if(b>m) ans+=query(a,b,k<<1|1,m+1,r);
return ans;
}
3.2二維樹狀陣列
int n, w, h, s, t;
int bit[maxn][maxn];
int lowbit(int x)
{
return x&(-x);
}
void add(int x, int y, int v)
{
for(int i = x; i <= h; i+=lowbit(i))
{
for(int j = y; j <= w; j+=lowbit(j))
{
bit[i][j] += v;
}
}
}
int query(int x, int y)
{
int res = 0;
for(int i = x; i; i-=lowbit(i))
{
for(int j = y; j; j-=lowbit(j))
{
res+=bit[i][j];
}
}
return res;
}
4.字串處理
4.1KMP演算法
//未改進的KMP演算法程式碼實現
void get_next(int *next, char *T, int len)
{
next[0] = -1;//-1代表沒有重複子串
int k = -1;
for (int q = 1; q <= len; q++)
{
while (k > -1 && T[k+1] != T[q])//下一個元素不相等,把k向前回溯
{
k = next[k];
}
if (T[k+1] == T[q])//下一個元素相等,所以最長重複子串+1
{
k = k+1;
}
next[q] = k;//給next陣列賦值
}
}
int KMP(char *s, int len, char *p, int plen)//利用KMP演算法匹配
{
int *next = new int(plen);
get_next(next, p, plen);
int k = -1;
int i = 0;
for (; i < len; i++)
{
while (k > -1 && p[k+1]!=s[i])//兩串下一個字元不相等,向前回溯(效率高就是在這裡,每次匹配失敗,
//k不用直接變為0,從第一個字元開始重新匹配,而是變為最長重複子串的下一個字元,從中間開始匹配即可)。
{
k = next[k];
}
if(p[k+1] == s[i])//兩個串的字元相等,k+1來匹配子串的一個字元
{
k++;
}
if (k == plen-1)//匹配成功,返回短串在長串的位置。
{
return i-plen+1;
}
}
return -1;
}
4.2Manacher演算法
/*
* 求最長迴文子串
*/
const int MAXN=110010;
char Ma[MAXN*2];
int Mp[MAXN*2];
void Manacher(char s[],int len){
int l=0;
Ma[l++]='$';
Ma[l++]='#';
for(int i=0;i<len;i++){
Ma[l++]=s[i];
Ma[l++]='#';
}
Ma[l]=0;
int mx=0,id=0;
for(int i=0;i<l;i++){
Mp[i]=mx>i?min(Mp[2*id−i],mx−i):1;
while(Ma[i+Mp[i]]==Ma[i−Mp[i]])Mp[i]++;
if(i+Mp[i]>mx){
mx=i+Mp[i];
id=i;
}
}
}
/*
* abaaba
* i: 0 1 2 3 4 5 6 7 8 9 10 11 12 13
* Ma[i]: $ # a # b # a # a # b # a #
* Mp[i]: 1 1 2 1 4 1 2 7 2 1 4 1 2 1
*/
char s[MAXN];
int main(){
while(scanf("%s",s)==1){
int len=strlen(s);
Manacher(s,len);
int ans=0;
for(int i=0;i<2*len+2;i++)
ans=max(ans,Mp[i]−1);
printf("%d\n",ans);
}
return 0;
}
5.搜尋
5.1廣搜
int move[4][2] = {1,0,0,1,-1,0,0,-1};//遍歷四個方向
struct node
{
int x, y, step;//x,y是座標,t是步數.
node(int _x, int _y, int _step){x = _x; y= _y; step=_step;}
node(){}
};
int h, w, sx, sy, gx, gy;
int map[500][500];
bool visit[500][500];
int bfs()
{
memset(visit, 0, sizeof(visit));
queue<node> que;//建立空佇列
node cor(sx,sy,0); //壓入起點
que.push(cor);
while (!que.empty())
{
node next = que.front();//下一個佇列元素
que.pop();//出隊
for (int i = 0; i < 4; i++)
{
int nx = cor.x+move[i][0], ny = cor.y+move[i][1];
if (0<=nx&&0<=ny&&nx<h&&ny<w&&!visit[nx][ny]) //保證新元素不越界並且沒有訪問過
{
visit[nx][ny] = true;
que.push(node(nx,ny,next.step+1));
if (nx == gx&& ny == gy)//滿足條件結束函式
{
return next.step+1;
}
}
}
}
return -1;
}
5.2二分查詢
/*
|二分搜尋|
|要求:先排序|
*/
// l為最開始元素, r是末尾元素,x是要找的數
int bsearch(int *A, int l, int r, int val){
int m;
while (l < r){
if(l==r)
{
if(A[l] == val)
return l;
else
return -1;
}
m = (l + r) / 2;
if (A[m] >= val) r = m; else l = m + 1;
}
return -1;
}
/*
最後l == r
如果找有多少的x,可以用lower_bound查詢一遍,upper_bound查詢一遍,下標相減
C++自帶的lower_bound(a,a+n,x)返回陣列中最後一個x的下一個數的地址
upper_bound(a,a+n,x)返回陣列中第一個x的地址
如果a+n內沒有找到x或x的下一個地址,返回a+n的地址
lower_bound(a,a+n,x)-upper_bound(a,a+n,x)返回陣列中x的個數
*/
6.其他
6.1標頭檔案及巨集定義
#include<bits/stdc++.h>
#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <malloc.h>
#include <iostream>
#include <algorithm>
#include <functional>
#define sdddd(x,y,z,k) scanf("%d%d%d%d", &x, &y, &z, &k)
#define sddd(x,y,z) scanf("%d%d%d", &x, &y, &z)
#define sdd(x,y) scanf("%d%d", &x, &y)
#define sd(x) scanf("%d", &x)
#define mp make_pair
#define pb push_back
#define lson k<<1
#define rson k<<1|1
#define mid (1+r)/2
#define ms(x, y) memset(x, y, sizeof x)
#define MOD 142857
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1000050;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
6.2輸入輸出加速
std::ios::sync_with_stdio(false);
6.3檔案輸入輸出
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
6.4STL庫
6.4.1set及multiset
//set及multiset用法(後者允許重複)
//主要函式:
begin() //返回指向第一個元素的迭代器
clear() //清除所有元素
count() //返回某個值元素的個數
empty() //如果集合為空,返回true
end() //返回指向最後一個元素的迭代器
erase() //刪除集合中的元素(引數是一個元素值,或者迭代器)
find() //返回一個指向被查詢到元素的迭代器
insert() //在集合中插入元素
size() //集合中元素的數目
lower_bound() //返回指向大於(或等於)某值的第一個元素的迭代器
upper_bound() //返回大於某個值元素的迭代器
equal_range() //返回集合中與給定值相等的上下限的兩個迭代器
//(注意對於multiset 刪除操作之間刪除值會把所以這個值的都刪掉,刪除一個要用迭代器)
6.4.2map
begin() //返回指向map頭部的迭代器
clear()// 刪除所有元素
count()// 返回指定元素出現的次數
empty() //如果map為空則返回true
end() //返回指向map末尾的迭代器
equal_range()// 返回特殊條目的迭代器對
erase() //刪除一個元素
find() //查詢一個元素
insert() //插入元素
lower_bound() //返回鍵值>=給定元素的第一個位置
max_size() //返回可以容納的最大元素個數
rbegin() //返回一個指向map尾部的逆向迭代器
rend() //返回一個指向map頭部的逆向迭代器
size() //返回map中元素的個數
swap()// 交換兩個map
upper_bound()// 返回鍵值>給定元素的第一個位置
value_comp() //返回比較元素value的函式
for(auto i = mp.begin(); i != mp.end(); i++)//遍歷,i為pair型別 訪問用'.'
map<int,string>::iterator it;
for(it = mp.begin(); it != mp.end(); it++)//遍歷,it為迭代器型別 訪問用'->'
for(auto it:mp)//遍歷,i為pair型別 訪問用'.'