ACM算法模板

1.头文件

#define _CRT_SBCURE_MO_DEPRECATE  
#include<iostream>  
#include<stdlib.h>  
#include<stdio.h>  
#include<cmath>  
#include<algorithm>  
#include<string>  
#include<string.h>  
#include<set>  
#include<queue>  
#include<stack>  
#include<functional>   
using namespace std;
const int maxn = 100 + 10;
const int INF = 0x3f3f3f3f;<span id="transmark" style="display: none; width: 0px; height: 0px;"></span>

2.筛选法求素数

伪代码
IS_PRIME(A)
  
for each i less than A.length + 1

      A[i] = 0
  for i = 2 to A.length + 1

      if A[i] = 0
          
for all multiples j of i,less than upper bound

              A[j] <- 1

代码

for (int i = 2; i < n; i++) {
	if (a[i] == 0) {
		for (int j = i + 1; j <= 10000; j = j + i) {
			a[j] = 1;
		}
	}
}

3.快速幂

快速幂公式:
typedef long long LL;//视情况定类型
LL fun(LL x, LL n) {
	LL res = 1;
	while (n > 0) {
		if (n & 1)//&按位与判奇偶  4>>1 = 4/2  2<<1 = 2*2
			res = (res*x);//求幂,所以无取模
		x = x*x;
		n >>= 1;
	}
	return res;
}

快速幂取模

int fun(int a, int b, int n) {
	int t = 1, y = a;
	while (b != 0){
		y %= n;
		if (b % 2 == 1)
			t = t%n*y%n;
		y = y*y%n;
		b = b >> 1;
	}
	return t;
}


4.模拟大数相加

<pre name="code" class="cpp">string add(string s1, string s2) {
	if (s1 == ""&&s2 == "") return "0";
	if (s1 == "")  return s2;
	if (s2 == "")  return s1;
	string max = s1, min = s2;
	if (s1.length() < s2.length()) {
		max = s2;
		min = s1;
	}
	int a = max.length() - 1;
	int b = min.length() - 1;
	for (int i = b; i >= 0; i--) {
		max[a--] += min[i] - '0';//a一直在减
	}
	for (int i = max.length(); i > 0; i--) {
		if (max[i] > '9') {
			max[i] = max[i] - 10;
			max[i - 1]++;
		}
	}
	if (max[0] > '9') {
		max[0] -= 10;
		max = '1' + max;
	}
	return max;
}


模拟大数阶乘:

int main()
{
	int large_num[16326] = { 1 };
	int num, zero = 0;
	int i, j, k, n;
	int top;

	scanf("%d", &num);
	for (i = 2, top = 1; i <= num; i++){
		k = i;
		while (k % 10 == 0){
			k /= 10;
			zero++;
		}
		for (j = 0; j < top; j++)
			large_num[j] *= k;

		for (n = 0; ; n++){
			large_num[n + 1] += large_num[n] / 10;
			large_num[n] %= 10;
			if (n + 1 == top){
				if (large_num[n + 1] != 0)
					top++;
				else
					break;
			}
		}
	}
	for (i = top - 1; i >= 0; i--)
		printf("%d", large_num[i]);
	for (i = 0; i < zero; i++)
		printf("0");
	printf("\n");
	return 0;
}


5.最大公约数

公约数求公倍数:乘积/最大公约数
int gad(int da, int xiao) {
	int temp;
	while (xiao!=0) {
		temp = da%xiao;
		da = xiao;
		xiao = temp;
	}
	return (da);
}

6.全排列
求1-n的全排列

void Perm(int list[], int k, int m) {
	if (k == m - 1) {
		for (int i = 0; i < m; i++) {
			printf("%d", list[i]);
		}
		printf("\n");
	}
	else {
		for (int i = k; i < m; i++) {
			swap(list[k], list[i]);
			Perm(list, k + 1, m);
			swap(list[k], list[i]);
		}
	}
}

7.二分搜索
int bsearch(int *A, int x, int y, int v) { 
x为最开始元素 y是末尾元素的下一个数 v是要找的数

	int m;
	while (x < y) {

		m = x + (y - x) / 2;

		if (A[m] >= v) y = m;  //如果要替换为 upper_bound, 改为:if(A[m] <= v) x = m+1;  else y = m;
		
                else x = m + 1;    
 
	}

	return x;

}  
//最后x == y
//
如果没有找到 135577找6,返回7
//
如果找有多少的v,可以用lower_bound查找一遍,upper_bound查找一遍,下标相减
//

lower_bound(a,a+n,v)返回数组中最后一个v的下一个数的地址

//upper_bound(a,a+n,v)返回数组中第一个v的地址
//如果a+n内没有找到v或v的下一个地址,返回a+n的地址

//lower_bound(a, a + n, v)-upper_bound(a, a + n, v)返回数组中v的个数

8.背包问题
01背包:

void bag01(int cost,int weight)
{
 for(i=v;i>=cost;i--)
  dp[i] = max(dp[i], dp[i-cost]+weight);
}

完全背包:

void complete(int cost,int weight)
{
 for(i=cost;i<=v;i++)
     dp[i] = max(dp[i], dp[i-cost]+weight);
}

多重背包:

void multiply(int cost,int weight,int amount)
{
 if(cost*amount>=v)
  complete(cost,weight);
 else{
  k=1;
  while(k<amount){
   bag01(k*cost,k*weight);
   amount-=k;
   k+=k;
  }
  bag01(cost*amount,weight*amount);
 }
}

9.LIS最长上升子序列

状态转移dp[i] = max{ 1.dp[j] + 1 }; j<i;a[j]<a[i];
d[i]是以i结尾的最长上升子序列
与i之前的 每个a[j]<a[i]的 j的位置的 最长上升子序列+1后 的值比较

void solve(){   // 参考挑战程序设计入门经典;

    for(int i = 0; i < n; ++i){

        dp[i] = 1;

        for(int j = 0; j < i; ++j){

            if(a[j] < a[i]){

                dp[i] = max(dp[i], dp[j]+1);

            }

        }

    }

}

优化方法
//dp[i]表示长度为i+1的上升子序列的最末尾元素;
//找到第一个比dp末尾大的,代替
void solve() {
	fill(dp, dp + n, INF);
	for (int i = 0; i < n; i++) {
		*lower_bound(dp, dp + n, a[i]) = a[i];//返回一个指针
	}
	printf("%d\n", *lower_bound(dp, dp + n, INF) - dp;
}
//函数lower_bound()返回一个 iterator 它指向在[first,last)标记的有序序列中可以插入value,而不会破坏容器顺序的第一个位置,而这个位置标记了一个不小于value 的值。



10.最长公共子序列
求最长公共子序列 递推
void solve() {

	for (int i = 0; i < n; ++i) {

		for (int j = 0; j < m; ++j) {

			if (s1[i] == s2[j]) {

				dp[i + 1][j + 1] = dp[i][j] + 1;

			}

			else {

				dp[i + 1][j + 1] = max(dp[i][j + 1], dp[i + 1][j]);

			}
		}

	}
}

11.并查集

int father[100];//储存i的father父节点

void makeSet() {
	for (int i = 0; i < 100; i++) 
		father[i] = i;
}

int findRoot(int x) { //递归查找根节点
	if (father[x] == x) 
		return x;
	else 
		return findRoot(father[x]);
}

int Find(int x) { // 路径压缩 递推 优化:关键在于在路径上的每个节点都可以直接连接到根上
	if (father[x] != x) father[x] = Find(father[x]);
	return father[x];
}
int DFind(int x) {//路径压缩 迭代 最优版
	int root = x; //根节点
	while (root != father[root]) { //寻找根节点
		root = father[root];
	}
	while (x != root) {
		int tmp = father[x];
		father[x] = root; //根节点赋值
		x = tmp;
	}
	return root;
}

void Union(int x, int y) {//将x所在的集合和y所在的集合整合起来形成一个集合。
	int a, b;
	a = findRoot(x);
	b = findRoot(y);
	father[a] = b;  //y连在x的根节点上   或father[b] = a为x连在y的根节点上;
}

12.并查集的MST——.Kruskal算法 (稀疏图)

第一步:点、边、加入vector,把所有边按从小到大排序

第二步:下面代码

void Kruskal() {  
    ans = 0;  
    for (int i = 0; i<len; i++) {  
        if (Find(edge[i].a) != Find(edge[i].b)) {  
            Union(edge[i].a, edge[i].b);  
            ans += edge[i].len;  
        }  
    }  
}  

13.并查集的MST——Prim算法 (稠密图)

时间复杂度:O(n方)

void Init()
{
	for (int i = 0; i < maxn; ++i) {
		G[i].clear();
		intree[i] = false;
		mindist[i] = INF;//初始化为最大值,因为开始的时候F为空,到V的任意节点都不连通,用INF表示
	}
}
int Prim(int s)//s是第一个加入生成树的结点
{
	int ans = 0;
	int vex, addNode, tempMin;//加入集合F中的节点

	intree[s] = true;//加入生成树
	for (unsigned int i = 0; i < G[s].size(); ++i) {//更新mindistG[s][i].vex即所有与s连通的节点vex
		vex = G[s][i].vex;
		mindist[vex] = G[s][i].weight;
	}
	for (int nodeNum = 1; nodeNum <= n - 1; ++nodeNum) {//对于集合V中剩余的n-1个节点
		tempMin = INF;
		for (int i = 1; i <= n; ++i) {//从集合V中找出到F最小距离的边,
			if (intree[i] == false && mindist[i] < tempMin) {
				tempMin = mindist[i];
				addNode = i;
			}
		}
		intree[addNode] = true;//addNode 加入集合F
		ans += tempMin;//此时tempMin是最小权值				   
		for (unsigned int i = 0; i < G[addNode].size(); ++i) {//addNode加入集合F后更新F到V的最小距离,这里最关键!
			vex = G[addNode][i].vex;
			if (intree[vex] == false && G[addNode][i].weight < mindist[vex])
				mindist[vex] = G[addNode][i].weight;
		}
	}
	return ans;
}

Prim算法优化版,用堆

时间复杂度:O(elgn)

struct node {
	int v, len;
	node(int v = 0, int len = 0) :v(v), len(len) {}
	bool operator < (const node &a)const {  //加入队列的元素自动按距离从小到大排序
		return len> a.len;
	}
};
void init() {
	for (int i = 0; i<maxn; i++) {
		G[i].clear();
		dis[i] = INF;
		vis[i] = false;
	}
}
void Prim(int s) {
	priority_queue<node>Q;//定义优先队列
	int ans = 0;
	Q.push(node(s,0)); //起点加入队列
	while (!Q.empty()) { 
		node now = Q.top(); Q.pop(); //取出距离最小的点
		int v = now.v;
		if (vis[v]) continue; //同一个节点,可能会推入2次或2次以上队列,这样第一个被标记后,剩下的需要直接跳过。
		vis[v] = true; //标记一下
		ans += now.len;
		for (int i = 0; i<G[v].size(); i++) { //开始更新
			int v2 = G[v][i].v;
			int len = G[v][i].len;
			if (!vis[v2] && dis[v2] > len) { 
				dis[v2] = len;
				Q.push(node(v2, dis[v2])); //更新的点加入队列并排序
			}
		}
	}
	printf("%d\n", ans);
}


14.单源最短路算法——Dijkstra
适用于边权为正、求从单个源点出发,到所有节点的最短路  有向图或者无向图

void init()
{
	for (int i = 0; i < maxn; i++) {
		intree[i] = false;
		G[i].clear();
		mindist[i] = INF;
	}
}

int Perim(int s, int t) {
	int ans = 0;
	int vex, addNode, tempMin;
	intree[s] = true;
	mindist[s] = 0;
	for (int i = 0; i < G[s].size(); i++) {//找开始点周围的路径并初始化
		vex = G[s][i].vex;
		mindist[vex] = Min(mindist[vex], G[s][i].weight);
	}
	for (int nodeNum = 1; nodeNum <= n - 1; nodeNum++) {//向周围n-1个点找
		tempMin = INF;
		for (int i = 0; i < n; i++) {
			if (intree[i] == false && mindist[i] < tempMin) {//寻找最短路径
				tempMin = mindist[i];
				addNode = i;
			}
		}
		intree[addNode] = true;
		for (int i = 0; i < G[addNode].size(); i++) {//更新
			vex = G[addNode][i].vex;
			if (intree[vex] == false && mindist[addNode] + G[addNode][i].weight < mindist[vex])
				mindist[vex] = mindist[addNode] + G[addNode][i].weight;
		}
	}
         return mindist[t];
}


二维数组+路径打印:

#include<stdio.h>
#include<string.h>
#define INF 100000000
#define maxn 1001
bool vis[maxn];
int adj[maxn][maxn],dis[maxn],pre[maxn];//pre[]记录前驱
int n, m;
void dijkstra(int v)
{
    int i, j, u , min;
    for(i=0;i<=n;i++)
    {
        dis[i]=adj[v][i];
        vis[i]=0;
        //if(i!=v&&adj[v][i]!=INF)pre[i] = v;
       // else pre[i] = -1;
    }
    vis[v]=1;dis[v]=0;
    for(i=1;i<n;i++)
    {
        min = INF;
        for(j=1;j<=n;j++)
        {
            if(!vis[j]&&min > dis[j])
            {
                min = dis[j];
                u = j;
            }
        }
        if(min == INF)break;
        vis[u]=1;
        for(j=1;j<=n;j++)
        {
            if(!vis[j]&&adj[u][j]!=INF&&dis[u]+adj[u][j]<dis[j])
            {
                dis[j] = adj[u][j] + dis[u];
              //  pre[j] = u;
            }
        }
    }
}
int main()
{
    int i, j, x, y, w;
    while(~scanf("%d%d",&n,&m)&&n)
    {
        for(i=0;i<=n;i++)
        {
            for(j=0;j<=n;j++)
                if(i==j)adj[i][j]=0;
                else adj[i][j] = INF;
        }
        while(m--)
        {
            scanf("%d%d%d",&x,&y,&w);
            adj[x][y] = w;
            adj[y][x] = w;
        }
        dijkstra(0);
        printf("%d\n",dis[n]);  //以下为输出路径
        /*int p, len=0, ans[maxn];
        p = n-1;
        while(p!=0)
        {
            ans[len++] = p;
            p = pre[p];

        }
        printf("0->");
        for(i=len-1;i>=0;i--)
            printf("%d",ans[i]);
        puts("");  */
    }
    return 0;
}


优化版:时间复杂度 O(elbn)

struct node {
	int v, len;
	node(int v = 0, int len = 0) :v(v), len(len) {}
	bool operator < (const node &a)const { //距离从小到大排序
		return len > a.len;
	}
};
vector<node>G[maxn];
bool vis[maxn];
int dis[maxn];
void init() {
	for (int i = 0; i<maxn; i++) {
		G[i].clear();
		vis[i] = false;
		dis[i] = INF;
	}
}
int dijkstra_heap(int s, int e) {
	priority_queue<node>Q;
	Q.push(node(s, 0));//加入队列并排序
	dis[s] = 0;
	while (!Q.empty()) {
		node now = Q.top(); //取出当前最小的
		Q.pop();
		int v = now.v;
		if (vis[v]) continue; //如果标记过了 直接continue
		vis[v] = true;
		for (int i = 0; i<G[v].size(); i++) { //更新
			int v2 = G[v][i].v;
			int len = G[v][i].len;
			if (!vis[v2] && dis[v2] > dis[v] + len) {
				dis[v2] = dis[v] + len;
				Q.push(node(v2, dis[v2]));
			}
		}
	}
	return dis[e];
}


15.Bellman-Ford算法的一种队列优化---SPFA 算法

时间复杂度减少,而且也可以处理负环的情况

//不断的将s的邻接点加入队列,取出不断的进行松弛操作,直到队列为空
//如果一个结点被加入队列超过n-1次,那么显然图中有负环
void Init()
{
    for(int i = 0 ; i < maxn ; ++i){
        G[i].clear();
        dist[i] = INF;
    }
}
int SPFA(int s,int e)
{
    int v1,v2,weight;
    queue<int> Q;
    memset(inqueue,false,sizeof(inqueue));//标记是否在队列中
    memset(cnt,0,sizeof(cnt));//加入队列的次数
    dist[s] = 0;
    Q.push(s);//起点加入队列
    inqueue[s] = true;//标记
    while(!Q.empty()){
        v1 = Q.front();
        Q.pop();
        inqueue[v1] = false;//取消标记
        for(int i = 0 ; i < G[v1].size() ; ++i){//搜索v1的链表
            v2 = G[v1][i].vex;
            weight = G[v1][i].weight;
            if(dist[v2] > dist[v1] + weight){ //松弛操作
                dist[v2] = dist[v1] + weight;
                if(inqueue[v2] == false){ //再次加入队列
                    inqueue[v2] = true;
                    //cnt[v2]++; 判负环
                    //if(cnt[v2] > n) return -1;
                    Q.push(v2);
                }
            }
        }
    }
    return dist[e];
}

16.Floyd-Warshall算法——任意点对最短路算法

求图中任意两点的最短距离的算法

for (int i = 0; i < n; i++) {//初始化为0
				for (int j = 0; j < n; j++)
					scanf("%lf", &dis[i][j]);
			}
			for (int k = 0; k < n; k++) {
				for (int i = 0; i < n; i++) {
					for (int j = 0; j < n; j++) {
						dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
					}
				}
			}

17.染色法判断二分图

int bipartite(int s) {
	int u, v;
	queue<int>Q;
	color[s] = 1;
	Q.push(s);
	while (!Q.empty()) {
		u = Q.front();
		Q.pop();
		for (int i = 0; i < G[u].size(); i++) {
			v = G[u][i];
			if (color[v] == 0) {
				color[v] = -color[u];
				Q.push(v);
			}
			else if (color[v] == color[u])
				return 0;
		}
	}
	return 1;
}

18.匈牙利算法 求解最大匹配问题

递归 腾

vector<int>G[maxn];
bool inpath[maxn];//标记
int match[maxn];//记录匹配对象
void init()
{
	memset(match, -1, sizeof(match));
	for (int i = 0; i < maxn; i++) {
		G[i].clear();
	}
}
bool findpath(int k) {
	for (int i = 0; i < G[k].size(); i++) {
		int v = G[k][i];
		if (!inpath[v]) {
			inpath[v] = true;
			if (match[v] == -1 || findpath(match[v])) {//递归
				match[v] = k;//即匹配对象是“k妹子”的
				return true;
			}
		}
	}
	return false;
}

void hungary() {
	int cnt = 0;
	for (int i = 1; i <= m; i++) { //m为需要匹配的“妹子”数
		memset(inpath, false, sizeof(inpath));//每次都要初始化
		if (findpath(i)) cnt++;
	}
	cout << cnt << endl;
}

dfs版:

int v1, v2;
bool Map[501][501];
bool visit[501];
int link[501];


int result;
bool dfs(int x)
{
    for (int y = 1; y <= v2; y++)
    {
        if (Map[x][y] && !visit[y])
        {
            visit[y] = true;
            if (link[y] == 0 || dfs(link[y]))
            {
                link[y] = x;
                return true;
            }
        }
    }
    return false;
}


void Search()
{
    for (int x = 1; x <= v1; x++)
    {
        memset(visit,false,sizeof(visit));
        if (dfs(x))
            result++;
    }
}
<pre><span style="color:#000000;">memset(Map,</span><span style="color:#800080;">0</span>,<span style="color:#0000ff;">sizeof</span><span style="color:#000000;">(Map));</span>

 

19.求多边形面积

struct node {
	double x;//横坐标
	double y;//纵坐标
};

node G[maxn];
int n;

double Cross(node a, node b) { //叉积计算
	return a.x*b.y - a.y*b.x;
}


int main()
{
	while (scanf("%d", &n) != EOF && n) {
		for (int i = 0; i < n; i++) 
			scanf("%lf %lf", &G[i].x, &G[i].y);
		double sum = 0;
		G[n].x = G[0].x;
		G[n].y = G[0].y;
		for (int i = 0; i < n; i++) { 
				sum += Cross(G[i], G[i + 1]);
		}
		//或者
			//for (int i = 0; i < n; i++) {
				//sum += fun(G[i], G[(i + 1)% n]);
			//}
		sum = sum / 2.0;
		printf("%.1f\n", sum);
	}
	system("pause");
	return 0;
}

20.向量基本用法
Vector operator + (Vector A, Vector B) { return Vector(A.x + B.x, A.y + B.y); }
Vector operator - (Point A, Point B) { return Vector(A.x - B.y, A.y - B.y); }
Vector operator * (Vector A, double p) { return Vector(A.x*p, A.y*p); }
Vector operator / (Vector A, double p) { return Vector(A.x / p, A.y*p); }

double Dot(Vector A, Vector B) { return A.x*B.x + A.y*B.y; }//向量点乘
double Length(Vector A) { return sqrt(Dot(A, A)); } //向量模长
double Angle(Vector A, Vector B) { return acos(Dot(A, B) / Length(A) / Length(B)); } //向量之间夹角

double Cross(Vector A, Vector B) { //叉积计算 公式
	return A.x*B.y - A.y*B.x;
}

Vector Rotate(Vector A, double rad)//向量旋转 公式
{
	return Vector(A.x*cos(rad) - A.y*sin(rad), A.x*sin(rad) + A.y*cos(rad));
}

Point getLineIntersection(Point P, Vector v, Point Q, Vector w)//两直线交点t1 t2计算  公式
{
	Vector u = P - Q; 
	double t = Cross(w, u) / Cross(v, w);  //求得是横坐标
	return P + v*t;  //返回一个点
}

21.判断线段相交

    struct node    
    {    
        double x,y;    
    };    
    node P[35][105];    
    double Cross_Prouct(node A,node B,node C)       //  计算BA叉乘CA;    
    {    
        return (B.x-A.x)*(C.y-A.y)-(B.y-A.y)*(C.x-A.x);    
    }    
    bool Intersect(node A,node B,node C,node D)     //  通过叉乘判断线段是否相交;    
    {    
        if(min(A.x,B.x)<=max(C.x,D.x)&&         //  快速排斥实验;    
           min(C.x,D.x)<=max(A.x,B.x)&&    
           min(A.y,B.y)<=max(C.y,D.y)&&    
           min(C.y,D.y)<=max(A.y,B.y)&&    
           Cross_Prouct(A,B,C)*Cross_Prouct(A,B,D)<0&&      //  跨立实验;    
           Cross_Prouct(C,D,A)*Cross_Prouct(C,D,B)<0)       //  叉乘异号表示在两侧;    
           return true;    
        else return false;    
    }  

22.求三角形外心

Point circumcenter(const Point &a, const Point &b, const Point &c)//返回三角形的外心   
{ 
	Point ret;
	double a1 = b.x - a.x, b1 = b.y - a.y, c1 = (a1*a1 + b1*b1) / 2;
	double a2 = c.x - a.x, b2 = c.y - a.y, c2 = (a2*a2 + b2*b2) / 2;
	double d = a1*b2 - a2*b1;
	ret.x = a.x + (c1*b2 - c2*b1) / d;
	ret.y = a.y + (a1*c2 - a2*c1) / d;
	return ret;
}

23.极角排序

double cross(point p1, point p2, point q1, point q2)//叉积计算
{
	return (q2.y - q1.y)*(p2.x - p1.x) - (q2.x - q1.x)*(p2.y - p1.y);
}
bool cmp(point a, point b)
{
	point o;
	o.x = o.y = 0;
	return cross(o, b, o, a) < 0; //叉积判断
}
sort(convex + 1, convex + cnt, cmp);//按角排序 从小到大

24.kmp算法

void getnext(int b[maxn], int next[maxm]) {  
    int j = 0, k = -1;  
    next[0] = -1;  
    while (j < m - 1) {//m是字符串长度       
        if (k == -1 || b[j] == b[k]) {  
            j++;  
            k++;  
            next[j] = k;  
        }  
        else  
            k = next[k];  
    }  
}  
  
void kmp(int a[maxn], int b[maxn]) {  
    int next[maxm];  
    int i = 0, j = 0;  
    getnext(b, next);  
    while (i < n) {  
        if (j == -1 || a[i] == b[j]) {//母串不动,子串移动  
            j++;  
            i++;  
        }  
        else {  
            // i不需要回溯了  
            // i = i - j + 1;  
            j = next[j];  
        }  
        if (j == m) {  
            printf("%d\n", i - m + 1);//母串的位置减去子串的长度+1  
            return;  
        }  
    }  
    printf("-1\n");  
}  
  


kmp扩展

#include<iostream>  
#include<cstring>  
using namespace std;  
const int MM=100005;  
  
int next[MM],extand[MM];  
  
char S[MM],T[MM];  
  
void GetNext(const char *T) {  
    int len = strlen(T),a = 0;  
  
    next[0] = len;  
  
    while(a < len - 1 && T[a] == T[a + 1]) a++;  
  
    next[1] = a;  
    a = 1;  
  
    for(int k = 2; k < len; k ++) {  
  
        int p = a + next[a] - 1,L = next[k - a];  
  
        if( (k - 1) + L >= p) {  
  
            int j = (p - k + 1) > 0 ? (p - k + 1) : 0;  
  
            while(k + j < len && T[k + j] == T[j]) j++;  
  
            next[k] = j;  
  
            a = k;  
  
        } else  
            next[k] = L;  
    }  
}  
  
void GetExtand(const char *S,const char *T) {  
    GetNext(T);  
  
    int slen = strlen(S),tlen = strlen(T),a = 0;  
  
    int MinLen = slen < tlen ? slen : tlen;  
  
    while(a < MinLen && S[a] == T[a]) a++;  
  
    extand[0] = a;  
  
    a = 0;  
  
    for(int k = 1; k < slen; k ++) {  
  
        int p = a + extand[a] - 1, L = next[k - a];  
  
        if( (k - 1) + L >= p) {  
  
            int j = (p - k + 1) > 0 ? (p - k + 1) : 0;  
  
            while(k + j < slen && j < tlen && S[k + j] == T[j]) j ++;  
  
            extand[k] = j;  
  
            a = k;  
  
        } else  
            extand[k] = L;  
    }  
}  
void show(const int *s,int len){  
  
    for(int i = 0; i < len; i ++)  
            cout << s[i] << ' ';  
    cout << endl;  
}  
  
int main() {  
    while(cin >> S >> T) {  
        GetExtand(S,T);  
        show(next,strlen(T));  
        show(extand,strlen(S));  
    }  
    return 0;  
} 



25.字典树

struct Trie{
    int cnt;
    Trie *next[maxn];
    Trie(){
        cnt = 0;
        memset(next,0,sizeof(next));
    }
};

Trie *root;


void Insert(char *word)
{
    Trie *tem = root;
    while(*word != '\0')
    {
        int x = *word - 'a';
        if(tem->next[x] == NULL)
            tem->next[x] = new Trie;
        tem = tem->next[x];
        tem->cnt++;
        word++;
    }
}

int Search(char *word)
{
    Trie *tem = root;
    for(int i=0;word[i]!='\0';i++)
    {
        int x = word[i]-'a';
        if(tem->next[x] == NULL)
            return 0;
        tem = tem->next[x];
    }
    return tem->cnt;
}

void Delete(char *word,int t)
{
    Trie *tem = root;
    for(int i=0;word[i]!='\0';i++)
    {
        int x = word[i]-'a';
        tem = tem->next[x];
        (tem->cnt)-=t;
    }
    for(int i=0;i<maxn;i++)
        tem->next[i] = NULL;
}

int main()
{
    int n;
    char str1[50];
    char str2[50];
    while(scanf("%d",&n)!=EOF)
    {
        root = new Trie;
        while(n--)
        {
            scanf("%s %s",str1,str2);
            if(str1[0]=='i')
                Insert(str2);
            else if(str1[0] == 's')
            {
                if(Search(str2))
                    printf("Yes\n");
                else
                    printf("No\n");
            }
            else
            {
                int t = Search(str2);
                if(t)
                    Delete(str2,t);
            }
        }
    }
    return 0;
}

26.AC自动机

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>

using namespace std;

#define N 1000010

char str[N], keyword[N];
int head, tail;

struct node
{
    node *fail;
    node *next[26];
    int count;
    node() //init
    {
        fail = NULL;//默认为空
        count = 0;
        for(int i = 0; i < 26; ++i)
            next[i] = NULL;
    }
}*q[N];

node *root;

void insert(char *str) //建立Trie
{
    int temp, len;
    node *p = root;
    len = strlen(str);
    for(int i = 0; i < len; ++i)
    {
        temp = str[i] - 'a';
        if(p->next[temp] == NULL)
            p->next[temp] = new node();
        p = p->next[temp];
    }
    p->count++;
}

void build_ac() //初始化fail指针,BFS 数组模拟队列:
{
    q[tail++] = root;
    while(head != tail)
    {
        node *p = q[head++]; //弹出队头
        node *temp = NULL;
        for(int i = 0; i < 26; ++i)
        {
            if(p->next[i] != NULL)
            {
                if(p == root) //第一个元素fail必指向根
                    p->next[i]->fail = root;
                else
                {
                    temp = p->fail; //失败指针
                    while(temp != NULL) //2种情况结束:匹配为空or找到匹配
                    {
                        if(temp->next[i] != NULL) //找到匹配
                        {
                            p->next[i]->fail = temp->next[i];
                            break;
                        }
                        temp = temp->fail;
                    }
                    if(temp == NULL) //为空则从头匹配
                        p->next[i]->fail = root;
                }
                q[tail++] = p->next[i]; //入队
            }
        }
    }
}

int query() //扫描
{
    int index, len, result;
    node *p = root; //Tire入口
    result = 0;
    len = strlen(str);
    for(int i = 0; i < len; ++i)
    {
        index = str[i] - 'a';
        while(p->next[index] == NULL && p != root) //跳转失败指针
            p = p->fail;
        p = p->next[index];
        if(p == NULL)
            p = root;
        node *temp = p; //p不动,temp计算后缀串
        while(temp != root && temp->count != -1)
        {
            result += temp->count;
            temp->count = -1;
            temp = temp->fail;
        }
    }
    return result;
}

int main()
{
    int num;
    head= tail = 0;
    root = new node();
    scanf("%d", &num);
    getchar();
    for(int i = 0; i < num; ++i)
    {
       scanf("%s",keyword);
        insert(keyword);
    }
    build_ac();
    scanf("%s", str);
    if(query())
        printf("YES\n");
    else
        printf("NO\n");
    return 0;
}

27.线段树

点更新

struct node{
    int l,r,maxn,sum;
}tree[N<<2];

void build(int m,int l,int r){
    tree[m].l = l;
    tree[m].r = r;
    if(l == r){
        tree[m].maxn = a[l];
        tree[m].sum = a[l];
        return ;
    }
    int mid = (l+r)>>1;
    build(m<<1,l,mid);
    build((m<<1)+1,mid+1,r);
    tree[m].maxn = max(tree[m<<1].maxn,tree[(m<<1)+1].maxn);
    tree[m].sum = tree[m<<1].sum + tree[(m<<1)+1].sum;
}

void update(int m,int a,int val){
    if(tree[m].l == a && tree[m].r == a){
        tree[m].maxn = val;
        tree[m].sum = val;
        return ;
    }
    int mid = (tree[m].l+tree[m].r)>>1;
    if(a <= mid)
        update(m<<1,a,val);
    else
        update((m<<1)+1,a,val);
    tree[m].maxn = max(tree[m<<1].maxn,tree[(m<<1)+1].maxn);
    tree[m].sum = tree[m<<1].sum + tree[(m<<1)+1].sum;
}

int query_max(int m,int l,int r){
    if(l == tree[m].l && r == tree[m].r)
        return tree[m].maxn;
        //return tree[m].sum;
    int mid = (tree[m].l+tree[m].r)>>1;
    if(r <= mid)
        return query_max(m<<1,l,r);
    if(l > mid)
        return query_max((m<<1)+1,l,r);
    return max(query_max(m<<1,l,mid), query_max((m<<1)+1,mid+1,r));
    //return query_sum(m<<1,l,mid) + query_sum((m<<1)+1,mid+1,r);
}

build(1,1,n);
update(1,a,b);
query(1,a,b);

区间更新

typedef long long ll;
const int maxn = 100010;

int t,n,q;
ll anssum;

struct node{
    ll l,r;
    ll addv,sum;
}tree[maxn<<2];

void maintain(int id)
{
    if(tree[id].l >= tree[id].r)
        return ;
    tree[id].sum = tree[id<<1].sum + tree[id<<1|1].sum;
}

void pushdown(int id)
{
    if(tree[id].l >= tree[id].r)
        return ;
    if(tree[id].addv){
        int tmp = tree[id].addv;
        tree[id<<1].addv += tmp;
        tree[id<<1|1].addv += tmp;
        tree[id<<1].sum += (tree[id<<1].r - tree[id<<1].l + 1)*tmp;
        tree[id<<1|1].sum += (tree[id<<1|1].r - tree[id<<1|1].l + 1)*tmp;
        tree[id].addv = 0;
    }
}

void build(int id,ll l,ll r)
{
    tree[id].l = l;
    tree[id].r = r;
    tree[id].addv = 0;
    tree[id].sum = 0;
    if(l==r)
    {
        tree[id].sum = 0;
        return ;
    }
    ll mid = (l+r)>>1;
    build(id<<1,l,mid);
    build(id<<1|1,mid+1,r);
    maintain(id);
}

void updateAdd(int id,ll l,ll r,ll val)
{
    if(tree[id].l >= l && tree[id].r <= r)
    {
        tree[id].addv += val;
        tree[id].sum += (tree[id].r - tree[id].l+1)*val;
        return ;
    }
    pushdown(id);
    ll mid = (tree[id].l+tree[id].r)>>1;
    if(l <= mid)
        updateAdd(id<<1,l,r,val);
    if(mid < r)
        updateAdd(id<<1|1,l,r,val);
    maintain(id);
}

void query(int id,ll l,ll r)
{
    if(tree[id].l >= l && tree[id].r <= r){
        anssum += tree[id].sum;
        return ;
    }
    pushdown(id);
    ll mid = (tree[id].l + tree[id].r)>>1;
    if(l <= mid)
        query(id<<1,l,r);
    if(mid < r)
        query(id<<1|1,l,r);
    maintain(id);
}

int main()
{
    scanf("%d",&t);
    int kase = 0 ;
    while(t--){
        scanf("%d %d",&n,&q);
        build(1,1,n);
        int id;
        ll x,y;
        ll val;
        printf("Case %d:\n",++kase);
        while(q--){
            scanf("%d",&id);
            if(id==0){
                scanf("%lld %lld %lld",&x,&y,&val);
                updateAdd(1,x+1,y+1,val);
            }
            else{
                scanf("%lld %lld",&x,&y);
                anssum = 0;
                query(1,x+1,y+1);
                printf("%lld\n",anssum);
            }
        }
    }
    return 0;
}

28.中国剩余定理

int CRT(int a[],int m[],int n)  
{  
    int M = 1;  
    int ans = 0;  
    for(int i=1; i<=n; i++)  
        M *= m[i];  
    for(int i=1; i<=n; i++)  
    {  
        int x, y;  
        int Mi = M / m[i];  
        extend_Euclid(Mi, m[i], x, y);  
        ans = (ans + Mi * x * a[i]) % M;  
    }  
    if(ans < 0) ans += M;  
    return ans;  
}
void extend_Euclid(int a, int b, int &x, int &y)
{
    if(b == 0)
    {
        x = 1;
        y = 0;
        return;
    }
    extend_Euclid(b, a % b, x, y);
    int tmp = x;
    x = y;
    y = tmp - (a / b) * y;
}





                
用于打比赛的ACM算法模板 常用函数与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. 最小点基,最小权点基
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. 最小点基,最小权点基
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值