ACM算法模板--BY Focus

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40758751/article/details/82810357

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类型 访问用'.'

猜你喜欢

转载自blog.csdn.net/qq_40758751/article/details/82810357
今日推荐