ACM算法模板--BY Focus

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

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ACM 算法模板集 Contents 一. 常用函数与STL 二. 重要公式与定理 1. Fibonacci Number 2. Lucas Number 3. Catalan Number 4. Stirling Number(Second Kind) 5. Bell Number 6. Stirling's Approximation 7. Sum of Reciprocal Approximation 8. Young Tableau 9. 整数划分 10. 错排公式 11. 三角形内切圆半径公式 12. 三角形外接圆半径公式 13. 圆內接四边形面积公式 14. 基础数论公式 三. 大数模板,字符读入 四. 数论算法 1. Greatest Common Divisor最大公约数 2. Prime素数判断 3. Sieve Prime素数筛法 4. Module Inverse模逆元 5. Extended Euclid扩展欧几里德算法 6. Modular Linear Equation模线性方程(同余方程) 7. Chinese Remainder Theorem中国余数定理(互素于非互素) 8. Euler Function欧拉函数 9. Farey总数 9. Farey序列构造 10. Miller_Rabbin素数测试,Pollard_rho因式分解 五. 图论算法 1. 最小生成树(Kruscal算法) 2. 最小生成树(Prim算法) 3. 单源最短路径(Bellman-ford算法) 4. 单源最短路径(Dijkstra算法) 5. 全源最短路径(Folyd算法) 6. 拓扑排序 7. 网络预流和最大流 8. 网络最小费用最大流 9. 网络最大流(高度标号预流推进) 10. 最大团 11. 二分图最大匹配(匈牙利算法) 12. 带权二分图最优匹配(KM算法) 13. 强连通分量(Kosaraju算法) 14. 强连通分量(Gabow算法) 15. 无向图割边割点和双连通分量 16. 最小树形图O(N^3) 17. 最小树形图O(VE) 六. 几何算法 1. 几何模板 2. 球面上两点最短距离 3. 三点求圆心坐标 4. 三角形几个重要的点 七. 专题讨论 1. 树状数组 2. 字典树 3. 后缀树 4. 线段树 5. 并查集 6. 二叉堆 7. 逆序数(归并排序) 8. 树状DP 9. 欧拉路 10. 八数码 11. 高斯消元法 12. 字符串匹配(KMP算法) 13. 全排列,全组合 14. 二维线段树 15. 稳定婚姻匹配 16. 后缀数组 17. 左偏树 18. 标准RMQ-ST 19. 度限制最小生成树 20. 最优比率生成树(0/1分数规划) 21. 最小花费置换 22. 区间K大数 23. LCA - RMQ-ST 24. LCA – Tarjan 25. 指数型母函数 26. 指数型母函数(大数据) 27. 单词前缀树(字典树+KMP) 28. FFT(大数乘法) 29. 二分图网络最大流最小割 30. 混合图欧拉回路 31. 无源汇上下界网络流 32. 二分图最小点权覆盖 33. 带约束的轨道计数(Burnside引理) 34. 三分法求函数波峰 35. 单词计数,矩阵乘法 36. 字符串和数值hash 37. 滚动队列,前向星表示法 38. 最小点基,最小权点基

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值