常用模板总结(持续更新)



【gcd】

int gcd(int n,int m){
	if(n%m==0)
		return m;
	else 
		return gcd(m,n%m);
}

【快速幂】

typedef long long ll;
ll pow_mod(ll x,ll n ,ll mod ){
	ll res=1;
	x=x%mod;
	while(n){
		if(n%2)
			res=res*x%mod;
		x=x*x%mod;
		n/=2;
	}
	return res;
}

【图论算法】

  • 【SPFA】

#include<iostream>  
#include<vector>  
#include<queue>  
#include<cstdio>  
#define INF 99999999  
using namespace std;  
const int maxn = 222;  
int mapp[maxn][maxn],n,m;  
int vis[maxn], dis[maxn];  
  
int SPFA(int st,int end){  
	for(int i=0;i<n;i++){ // 初始化  
		dis[i] = INF; vis[i] = 0;//G[i].clear();  
	}  
	queue<int>Q;  
	dis[st] = 0;   
	vis[st] = 1; //起始点距离为0, 标记上  
	Q.push(st);  
	while(!Q.empty()){  
		int vex = Q.front(); Q.pop();  
		vis[vex] = 0; //    
		for(int i=0;i<n;i++){  
			if( dis[i] > mapp[vex][i] + dis[vex]){  
				dis[i] = mapp[vex][i] + dis[vex];  
				if(!vis[i]){  
					vis[i] = 1;  
					Q.push(i);  
				}  
			}  
		}  
	}  
	return dis[end];  
}  
int main()  
{  
	while(scanf("%d%d",&n,&m)!=EOF){  
		for(int i=0;i<n;i++)  
			for(int j=0;j<n;j++)  
				mapp[i][j] = INF;  
		int a,b,c;  
		for(int i=0;i<m;i++){  
			scanf("%d%d%d",&a,&b,&c);  
			if(c < mapp[a][b])  
				mapp[a][b] = mapp[b][a] = c;  
		}  
		int s,e;   
		scanf("%d%d",&s,&e);  
		int ans = SPFA(s,e);  
		if(ans < INF) printf("%d\n",ans);  
		else  
			printf("-1\n");  
	}  
}  


  • 【Dijkstra】

#include<iostream>  
#include<vector>  
#include<queue>  
#include<cstdio>  
#include<cstring>  
#define INF 0xfffffff  
using namespace std;  
const int maxn = 222;  
int n,m;  
int map[maxn][maxn];  
int dis[maxn];  
bool vis[maxn];  
int dijkstra(int st,int end){  
	memset(vis,0,sizeof(vis));  
	vis[st] = 1;  
	for(int i=0;i<n;i++){  
		dis[i] = map[st][i];  
	}  
	dis[st] = 0;  
	for(int num = 1;num<n;num++){ //找到其余的n-1个点  
		int tmp = INF, k;  
		for(int i=0;i<n;i++){  
			if(!vis[i] && tmp > dis[i]){  
				tmp = dis[i];  
				k = i;  
			}  
		}  
		vis[k] = true;  
		if(tmp == INF) break; // 当前没有找到最短的节点  
		for(int i=0;i<n;i++)  
			if(!vis[i] && dis[i] > dis[k] + map[k][i] )  
				dis[i] = dis[k] + map[k][i];   
	}  
	return dis[end];  
}  
int main(){  
	while(scanf("%d%d",&n,&m)!=EOF){  
		for(int i=0;i<n;i++)  
			for(int j=0;j<n;j++)  
				map[i][j] = (i == j)? 0:INF;   
		int a,b,c;  
		for(int i=0;i<m;i++){  
			scanf("%d%d%d",&a,&b,&c);  
			if(c< map[a][b])  
				map[a][b] = map[b][a] = c;  
		}  
		int s,e; scanf("%d%d",&s,&e);  
		int ans = dijkstra(s,e);  
		if(ans == INF)  
			printf("-1\n");  
		else  
			printf("%d\n",ans);  
	}  
	return 0;  
}  



  • 【Floyd-Warshall算法】

#include<iostream>  
#include<vector>  
#include<queue>  
#include<cstdio>  
#define INF 0xfffffff  
using namespace std;  
const int maxn = 222;  
int n,m;  
int map[maxn][maxn];  
void floyed(){ //k ,i ,j  
	for(int k=0;k<n;k++)  
		for(int i=0;i<n;i++)  
			for(int j=0;j<n;j++)  
				if(map[i][j] > map[i][k] + map[k][j])  
					map[i][j] = map[i][k] + map[k][j];  
}  
int main()  
{  
	while(scanf("%d%d",&n,&m)!=EOF){  
		for(int i=0;i<n;i++)  
			for(int j=0;j<n;j++)  
				if(i == j) map[i][j] = 0;  
				else map[i][j] = INF;  
		int a,b,c;  
		for(int i=0;i<m;i++){  
			scanf("%d%d%d",&a,&b,&c);  
			if(c < map[a][b]) //重边  
				map[a][b] = map[b][a] = c;  
		}  
		int s,e; scanf("%d%d",&s,&e);  
		floyed();  
		if(map[s][e] == INF)  
			printf("-1\n");  
		else  
			printf("%d\n",map[s][e]);  
	}  
	return 0;  
}  



  • 【Kruskal算法 最小生成树】

struct node{
    int v1,v2,len;
}edge[maxn];
void init(){
    for(int i=1;i<=n;i++){
        father[i] = i;
    }
}
int Find(int x){
    int r= x;
    while(r != father[r])
        r = father[r];
    while(x != r){
        int tmp = father[x];
        father[x] = r;
        x = tmp;
    }
    return r;
}
int Find(int x){
    if(x == father[x]) return x;
    else
        return father[x] = Find(father[x]);
}
void Union(int x,int y){
    int xr = Find(x);
    int yr = Find(y);
    if(xr == yr) return;
    else
      father[xr] = yr;
}
void Kruskal(){ // Kruskal 算法
    int edgenum=0;
    for(int i=0;i<len&& edgenum!=n-1;i++){
        if(Find(edge[i].v1)!=Find(edge[i].v2)){
            ans += edge[i].len;
            Union(edge[i].v1,edge[i].v2);
            edgenum++;
        }
    }
}



  • 【PRIM 最小生成树】

注意,不能判环

#define INF 0xfffffff
struct node{
    int v,len;
    node(int v=0, int len = 0):v(v),len(len){}
};
vector <node> G[maxn];
int intree[maxn];
int minDist[maxn];
void init(){
    for(int i=0;i<maxn;i++){
        intree[i]=0;
        G[i].clear();
        minDist[i]=INF;
    }
}
int prim(int s){
    intree[s]=1;
    int ans=0;
    for(int i=0;i<G[s].size();i++){
        int vex = G[s][i].v;
        minDist[vex] = min(G[s][i].len,minDist[vex]); //判重边
    }
    for(int nodeNum=0;nodeNum<n-1;nodeNum++){
        int tmpMin=INF;
        int addNode;
        for(int i=1;i<=n;i++){ //从1 到 n 的城市标号 
            if(!intree[i]&&minDist[i]<tmpMin){
                tmpMin=minDist[i];
                addNode = i;
            }
        }
        if(tmpMin==INF) {
            return -1;
        }
        ans+=tmpMin;
        intree[addNode]=1;
        for(int i=0;i<G[addNode].size();i++){
            int vex = G[addNode][i].v;
            if(!intree[vex]&&G[addNode][i].len<minDist[vex])
                minDist[vex] = G[addNode][i].len;
        }
    }
    return ans;
}


  • 【匈牙利算法】二分图最大匹配

int findpath(int k){
	for(int i=head[k];i!=-1;i=edge[i].next){
		int v = edge[i].to;
		if(!inpath[v]){
			inpath[v]=1;
			if(match[v]==-1||findpath(match[v])){
				match[v]=k;return true;
			}
		}
	}
	return false;
}
void hungary(){
	int ans=0;
	for(int i=1;i<=n;i++){
		memset(inpath,0,sizeof(inpath));
		if(findpath(i)){ //寻找增广路
			ans++;
		}
	}
	cout<<ans<<endl;
}
void init(){
	memset(head,-1,sizeof(head));
	memset(match,-1,sizeof(match));
	edgeNum=0;
}


数据结构

  • 【线段树点更新,区间查询】

#define L(m) m<<1  
#define R(m) m<<1|1  
const int maxn = 1000000+1;  
int num[maxn];  
struct node{  
    int l,r,sum;  
}tree[maxn<<2]; //开4倍数组  
void Build(int m,int l,int r){  
    tree[m].l=l; tree[m].r=r; //赋初值  
    if(tree[m].l==tree[m].r)  
    {  
        tree[m].sum=num[l]; return ;//不要忘了return  
    }  
    int mid = (tree[m].l+tree[m].r)>>1;  
    Build(L(m),l,mid);  //递归构造左右子树  
    Build(R(m),mid+1,r);  
    tree[m].sum = tree[L(m)].sum+tree[R(m)].sum; //回溯,将子节点的sum加到父节点上  
}  
void Update(int m,int a,int x){  
    if(tree[m].l==a && tree[m].r==a){  
        tree[m].sum+=x; return ; //这个return 忘了写找了好久的错  
    }  
    int mid = (tree[m].l+tree[m].r)>>1;   
    if(mid>=a)  
        Update(L(m),a,x);  
    else  
        Update(R(m),a,x);  
    tree[m].sum=tree[L(m)].sum+tree[R(m)].sum;  
}  
int Query(int m,int l,int r){  
    if(tree[m].l==l && tree[m].r==r){  
        return tree[m].sum;  
    }  
    int mid = (tree[m].l+tree[m].r)>>1;  
    if(mid>=r)                        //这里也可以写成 if else if else   
        return Query(L(m),l,r);  
    if(mid<l)  
        return Query(R(m),l,r);  
    return Query(L(m),l,mid)+Query(R(m),mid+1,r);  
}  

  • 【线段树区间修改,点查询】

#define L(m) m<<1  
#define R(m) m<<1|1  
using namespace std;  
const int maxn  =100000+10;  
typedef long long ll;  
ll num[maxn];  
struct node{  
    ll l,r,sum;  
    ll add;  
}tree[maxn<<2];  
void pushup(ll m){  
    tree[m].sum = tree[L(m)].sum + tree[R(m)].sum;  
}  
void pushdown(ll m){  
    if(tree[m].add){  
        ll tmp = tree[m].add;  
        tree[L(m)].sum += (tree[L(m)].r-tree[L(m)].l+1)*tmp;  
        tree[R(m)].sum += (tree[R(m)].r-tree[R(m)].l+1)*tmp;  
        tree[L(m)].add +=tmp; //所有的都是 += ;  
        tree[R(m)].add +=tmp;  
        tree[m].add = 0;  
    }  
}  
void Update(ll m,ll l,ll r,ll x){  
    if(tree[m].l >=l && tree[m].r <=r){  
        tree[m].add += x; //注意这里是+= 不是 =   
        tree[m].sum += (tree[m].r - tree[m].l + 1) *x;  
        return ;  
    }  
    pushdown(m);  
    ll mid = (tree[m].l + tree[m].r)>>1;  //这里取中间取得是当前节点左右区间的中点  
    if(mid>=r) 如果要更新的区间在左边  
         Update(L(m),l,r,x);  
    else if(mid<l)  
        Update(R(m),l,r,x);  
    else{   
        Update(L(m),l,mid,x);  
        Update(R(m),mid+1,r,x);  
    }  
    pushup(m);  
}  
ll Query(ll m,ll l,ll r){  
    if(tree[m].l==l && tree[m].r==r){  
        return tree[m].sum;  
    }  
    pushdown(m);  
    ll mid = (tree[m].l+ tree[m].r)>>1;  
    if(mid>=r)  
        return Query(L(m),l,r);  
    if(mid<l)  
        return Query(R(m),l,r); //这里也可以写成 if else else if  
    return Query(L(m),l,mid)+Query(R(m),mid+1,r);  
}  
void Build(ll m,ll l,ll r){  
    tree[m].l = l,tree[m].r = r;  
    tree[m].add=0;  //不要忘了初始化  
    if(l == r){  
        tree[m].add = 0;  
        tree[m].sum = num[l];  
        return ;  
    }  
    int mid = (l + r)>>1;  
    Build(L(m),l,mid);  
    Build(R(m),mid+1,r);  
    pushup(m);  
}  
  • 【线段树模板2,单点更新】

#include<cstring>
#include<iostream>
#include<cstdio>
using namespace std;
#define maxn 50005
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int sum[maxn<<2];
void Pushup(int rt){
	sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
void Build(int l,int r,int rt){
	if(l == r){
		scanf("%d",&sum[rt]);
	}
	else{
		int m = (l + r)>>1;
		Build(lson);
		Build(rson);
		Pushup(rt);
	}
}
void Update(int p,int add,int l,int r,int rt){
	if(l == r){
		sum[rt] += add;
	}
	else{
		int m = (l + r)>>1;
		if(p <=m)
			Update(p,add,lson);
		else
			Update(p,add,rson);
		Pushup(rt);
	}
}
int Query(int L,int R,int l,int r,int rt){ //L ,R为查询范围
	if(L <= l && r <=R){
		return sum[rt];
	}
	int m = (l + r)>>1;
	int ans = 0;
	if(L<=m)
		ans += Query(L,R,lson);
	if(R>m)
		ans += Query(L,R,rson);
	return ans;
} 
int main(){
	int t;
	scanf("%d",&t);
	for(int cas=1;cas<=t;cas++){
		printf("Case %d:\n",cas);
		int n,a,b;
		scanf("%d",&n);
		Build(1,n,1);
		char s[10];
		while(scanf("%s",s)!=EOF){
			if(s[0] == 'E') break;
			if(s[0] == 'A'){
				scanf("%d%d",&a,&b);
				Update(a,b,1,n,1);
			}
			else if(s[0] == 'S'){
				scanf("%d%d",&a,&b);
				Update(a,-b,1,n,1);
			}
			else if(s[0] == 'Q'){
				scanf("%d%d",&a,&b);
				printf("%d\n",Query(a,b,1,n,1));
			}
		}
	}
}

  • 【线段树模板2,区间修改】

#include <cstdio>  
#include <algorithm>  
using namespace std;  
   
#define lson l , m , rt << 1  
#define rson m + 1 , r , rt << 1 | 1  
#define LL long long  
const int maxn = 111111;  
LL add[maxn<<2];  
LL sum[maxn<<2];  
void PushUp(int rt) {  
	sum[rt] = sum[rt<<1] + sum[rt<<1|1];  
}  
void PushDown(int rt,int m) {  
	if (add[rt]) {  
		add[rt<<1] += add[rt];  
		add[rt<<1|1] += add[rt];  
		sum[rt<<1] += add[rt] * (m - (m >> 1));  
		sum[rt<<1|1] += add[rt] * (m >> 1);  
		add[rt] = 0;  
	}  
}  
void build(int l,int r,int rt) {  
	add[rt] = 0;  
	if (l == r) {  
		scanf("%lld",&sum[rt]);  
		return ;  
	}  
	int m = (l + r) >> 1;  
	build(lson);  
	build(rson);  
	PushUp(rt);  
}  
void update(int L,int R,int c,int l,int r,int rt) {  
	if (L <= l && r <= R) {  
		add[rt] += c;  
		sum[rt] += (LL)c * (r - l + 1);  
		return ;  
	}  
	PushDown(rt , r - l + 1);  
	int m = (l + r) >> 1;  
	if (L <= m) update(L , R , c , lson);  
	if (m < R) update(L , R , c , rson);  
	PushUp(rt);  
}  
LL query(int L,int R,int l,int r,int rt) {  
	if (L <= l && r <= R) {  
		return sum[rt];  
	}  
	PushDown(rt , r - l + 1);  
	int m = (l + r) >> 1;  
	LL ret = 0;  
	if (L <= m) ret += query(L , R , lson);  
	if (m < R) ret += query(L , R , rson);  
	return ret;  
}  
int main() {  
	int N , Q;  
	scanf("%d%d",&N,&Q);  
	build(1 , N , 1);  
	while (Q --) {  
		char op[2];  
		int a , b , c;  
		scanf("%s",op);  
		if (op[0] == 'Q') {  
			scanf("%d%d",&a,&b);  
			printf("%lld\n",query(a , b , 1 , N , 1));  
		} else {  
			scanf("%d%d%d",&a,&b,&c);  
			update(a , b , c , 1 , N , 1);  
		}  
	}  
	return 0;  
}  


【KMP】

#include <iostream>
#include <cstdio>
using namespace std;
const int maxn =1000005;
const int maxb =10005;
int a[maxn],b[maxb];
int nextv[maxb];
void get_next(int b[],int m){ //求模式串的 next数组
	int i=0;//前缀
	nextv[0]=-1;
	int j=-1;//后缀
	while(i<m){
		if(j==-1||b[i]==b[j]){
			i++; j++;
			if(b[i]==b[j]) //遇到相同元素的优化
				nextv[i]=nextv[j];
			else
				nextv[i]=j;
		}
		else
			j=nextv[j];
	}
}
void getPrenext(int b[],int m){ //未优化的getnext , 可以求模式串前后缀相同次数
	int i = 0, j = -1;
	next[0] = -1;
	while(i<m){
		if(j == -1 || b[i] == b[j]){
			nextv[++i] = ++j;
		}
		else
			j = nextv[j];
	}
}
int KMP(int n,int m){
	int i=0;
	int j=0;
	while(i<n&&j<m){
		if(j==-1||a[i]==b[j]){
			i++;j++;
		}
		else{
			j=nextv[j];
		}
	}
	if(j==m){ //只有匹配出结果j才能==m
		// cout<<"i: "<<i<<" "<<j<<endl;
		return i-m+1;
	}
	else return -1;
}


AC自动机


#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
struct node{
	node *next[26];
	int count ; //记录
	node* fail;
	node(){
		count = 0;
		fail = NULL;
		memset(next,0,sizeof(next));
	}
}*q[5000000];
int head,tail;
char str[1000010];
node *root;
void insert(char *s){ //构建trie
	int len = strlen(s);
	node *p = root;
	for(int i=0;i<len;i++){
		int index = s[i]-'a';
		if(!p->next[index])
			p->next[index] = new node;
		p=p->next[index];
	}
	p->count++;
}
void build_ac_automation(){ //初始化fail指针
	q[tail++] = root;
	while(head<tail){
		node *p = q[head++];
		node *tmp = NULL;
		for(int i=0;i<26;i++){
			if(p->next[i] != NULL){
				if(p == root)//首元素必须指根
					p->next[i]->fail = root;
				else{
					tmp =  p->fail; //失败指针(跳转指针)
					while(tmp != NULL){
						if(tmp->next[i] != NULL){//找到匹配
							p->next[i]->fail = tmp->next[i];
							break;
						} //如果没找到,则继续向上一个失败指针找
						tmp = tmp->fail;
					}
					if(tmp == NULL) //为空 则从头匹配
						p->next[i]->fail = root;
				}
				q[tail++] = p->next[i];//下一层入队
			}
		}
	}
}
int query(){
	int len = strlen(str);
	node *p = root;
	int cnt = 0;
	for(int i=0;i<len;i++){
		int index = str[i]-'a';
		while(p->next[index] == NULL && p!=root)
			p = p->fail;
		p = p->next[index];
		if(p == NULL)
			p = root;
		node *tmp = p;//tmp 动 , p不动。
		while(tmp != root && tmp->count != -1){
			cnt += tmp->count;
			tmp->count = -1;
			tmp = tmp ->fail; 
		}
	}
	return cnt;
}
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		 head= tail = 0;
		root = new node;
		int n;
		scanf("%d",&n);
		char s[10010];
		for(int i=0;i<n;i++){
			scanf("%s",s);
			insert(s);
		} 
		build_ac_automation();
		scanf("%s",str);
		int ans = query();
		printf("%d\n",ans);
	}
	return 0;
}


最小表示法

int minRepresentation(char *s){  
    int i=0,j=1,k=0;  
    while(i<len && j<len && k<len){  
        int tmp = s[(i + k)%len] - s[(j + k)%len];  
        if(tmp == 0) k++; //相等  
        else{  
            if(tmp > 0)   //改成 tmp > 0 就是最大表示法了
                i += k+1; // i = i + k + 1;  
            else  
                j += k+1;  
            if(i == j) j++;  
            k = 0;  
        }  
    }  
    return min(i,j);   //返回字典序最小的下标
}  



posted @ 2015-08-08 08:14  编程菌  阅读(187)  评论(0编辑  收藏  举报