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


【常用数据范围】

int ~ 2 * 10^9   long long 9 * 10^18

最近经常别 bool数组给忽悠,该bool的bool,该int的int。。

【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 = -1;
        for(int i=0;i<n;i++){
            if(!vis[i] && tmp > dis[i]){
                tmp = dis[i];
                k = i;
            }
        }
        if(k == -1) break; // 当前没有找到最短的节点
        vis[k] = true;
        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;
}




  • 【Dijkstra堆优化 (n + m)logn】

#include <cstdio>
#include <vector>
#include <queue>
#include <algorithm>
#define MAXN 200 + 10
#define INF 0xffffff
using namespace std;
struct node{
    int v, len;
    bool operator < (const node & t) const{
        return len > t.len;
    }
    node(int v = 0, int len = 0):v(v), len(len){}
};
vector<node> G[MAXN];
bool vis[MAXN];
int dis[MAXN];int n,m;
void Init(int n){
    for(int i = 0; i <= n; i++){
        G[i].clear();
    }
}
int dijstra_heap(int s,int t){  
    for(int i = 0; i <= n; i++){
        vis[i] = false;
        dis[i] = INF;
    }
    priority_queue<node>Q;
    dis[s] = 0;
    Q.push(node(s,0));
    while(!Q.empty()){
        node now = Q.top();
        Q.pop();
        int v = now.v;
        if(vis[v]) 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[v] + len <dis[v2]){
                dis[v2] = dis[v] + len ;
                Q.push(node(v2,dis[v2])); //讲 dis[v2]放入堆中,利用logn的效率找到
                                            //距离最短的节点
            }
        }
    }
    return dis[t];
}
int main(){
    int v1, v2, x, s, t;
    while(scanf("%d%d", &n, &m) != EOF){
        Init(n);
        for(int i = 0; i < m; i++){
            scanf("%d%d%d", &v1, &v2, &x);
            G[v1].push_back(node(v2, x));
            G[v2].push_back(node(v1, x));
        }
        scanf("%d%d", &s, &t);
        int ans = dijstra_heap(s, t, n);
        if(ans == INF)
            printf("-1\n");
        else
            printf("%d\n", ans);
    }
    return 0;
}


  • 【Floyd-Warshall算法 n ^ 3】
#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 0x3f3f3f3f
struct node{
    int v,len;
    node(int v=0, int len = 0):v(v),len(len){}
};
vector <node> G[maxn];
int vis[maxn];
int dis[maxn];
void init(){
    for(int i=0;i<maxn;i++){
        vis[i]=0;
        G[i].clear();
        dis[i]=INF;
    }
}
int prim(int s){
    vis[s]=1;
    int ans=0;
    for(int i=0;i<G[s].size();i++){
        int vex = G[s][i].v;
        dis[vex] = min(G[s][i].len,dis[vex]); //判重边
    }
    for(int nodeNum=0;nodeNum<n-1;nodeNum++){
        int tmpMin=INF;
        int addNode=-1;
        for(int i=1;i<=n;i++){ //从1 到 n 的城市标号 
            if(!vis[i]&&dis[i]<tmpMin){
                tmpMin=dis[i];
                addNode = i;
            }
        }
        if(addNode==-1) {
            return -1;
        }
        ans+=tmpMin;
        vis[addNode]=1;
        for(int i=0;i<G[addNode].size();i++){
            int vex = G[addNode][i].v;
            if(!vis[vex]&&G[addNode][i].len<dis[vex])
                dis[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;
}




  • 【tarjan】求强连通分量
#include<cstdio> // 顶点从0 - n-1
#include<algorithm>
#include<vector>
#include<iostream>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define INF 0x3f3f3f3f
#define mem(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
const int N = 100010;
int low[N];//当前能回溯到的栈中最小的次序号
int pre[N]; // 记录当前节点的次序号。(时间戳)
int scc[N];//记录节点所属强连通分量
stack<int>st;//栈中储存当前未处理的节点(访问了,但并没有划分为连通分量)
int dfs_num;//次序号
int cnt;//强连通分量的编号 1 ~ maxNumberOfSCC
int n,m;
int dis[N];
vector<int>V[N],G[N];
void init(){
    mem(low,0);mem(pre,0);mem(scc,0);
    dfs_num = 0; cnt = 0;
    while(!st.empty()) st.pop();
    for(int i=0;i<=n;i++){
        V[i].clear();G[i].clear();
    }
}
void tarjan(int x){
    pre[x] = low[x] = ++dfs_num;
    st.push(x);
    for(int i=0;i<V[x].size();i++){
        int v = V[x][i];
        if(!pre[v]){//没有访问过
            tarjan(v);
            low[x] = min(low[x],low[v]);
        }
        else if(!scc[v]){// 访问过了,但是没有划分联通分量,
                //也就是在栈中
            low[x] = min(low[x],pre[v]); // pre[v],v节点的时间戳
        }
    }
    if(low[x] == pre[x] ){//当前的次序号等于 能回溯到的最小次序号
                     //说明找到了”根“节点
        cnt++;
        while(1){
             int tmp = st.top(); st.pop();
             scc[tmp] = cnt;
             if(tmp == x) break;
        }
    }
}
int bfs(int x){
    queue<int>Q;
    Q.push(x);
    mem(dis,-1);
    dis[x] = 0;
    while(!Q.empty()){
        int u = Q.front();Q.pop();
        for(int i=0;i<G[u].size();i++){
            int v = G[u][i];
            if(dis[v] == -1){
                dis[v] = dis[u] + 1;
                if(v == scc[n-1]) return dis[v];
                Q.push(v);
            }
        }
    }
    return dis[scc[n-1]];
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        init();
        int a,b;
        for(int i=0;i<m;i++){
            scanf("%d%d",&a,&b);
            V[a].push_back(b);
        }
        for(int i=0;i<n;i++){
            if(!pre[i])
                tarjan(i);//缩点
        }
        for(int i=0;i<n;i++){ //重新构图
            for(int j=0;j<V[i].size();j++){
                int v = V[i][j];
                if(scc[i] != scc[v])
                    G[scc[i]].push_back(scc[v]);
            }
        }
        int ans = bfs(scc[0]);
        printf("%d\n",ans);
    }
}


数据结构

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

#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];  
    }  
}  
int KMP(int n,int m){  
    int i=0;  
    int j=0;  int cnt = 0;
    while(i<n&&j<m){  
        if(j==-1||a[i]==b[j]){  
            i++;j++;  
        }  
        else{  
            j=nextv[j];  
        }
        /* //find match's times
            if(j==m){
                cnt++;
                j = nextv[j];
            }
        */
    }  
    if(j==m){ //只有匹配出结果j才能==m  
        // cout<<"i: "<<i<<" "<<j<<endl;  
        return i-m+1;  
    }  
    else return -1;  
}  
int main(){  
    int T,n,m;  
    scanf("%d",&T);  
    while(T--){  
        scanf("%d%d",&n,&m);  
        for(int i=0;i<n;i++){  
            scanf("%d",&a[i]);  
        }  
        for(int i=0;i<m;i++){  
            scanf("%d",&b[i]);  
        }  
        get_next(b,m); //模式串 partern  
        int ans=KMP(n,m);  
        cout<<ans<<endl;  
    }  
    return 0;  
}  


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);   //返回字典序最小的下标
}  




【杂项】

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
//字符串 转 数字 sscanf("12.24","%lf",&num);
//或者 atoi(char *s); atof(char *s)//stdlib.h
//数字转字符串
//sprintf(char *s,"%d",num)
int main()
{
    double t;
    sscanf("12.24","%lf",&t);
    cout<<t<<endl;
    double num1 = atof("12");
    int num2 = atoi("123");
    cout<<num1<<" "<<num2<<endl;
    char s[1010];
    sprintf(s,"%.2lf",t);
    cout<<s<<endl;
    return 0;
}

计算几何模板
#include<iostream>
#include<cstdio>
#include<cmath>
using  namespace std;
const double eps = 1e-10;

int dcmp(double x){
    if(fabs(x) < eps) return 0;
    return x < 0 ? -1:1;
}
struct Point{
    double x,y;
    Point(double x = 0,double y = 0):x(x),y(y){}

    bool operator <(const Point& b)const{
        return x < b.x || (x == b.x && y < b.y);
    }
    bool operator == (const Point &b)const {
        return dcmp(x - b.x) == 0&& dcmp(y - b.y) == 0;
    }

};
typedef Point Vector  ;
// 求向量 (x,y)的极角,atan2(y,x); -- C标准库
    Vector operator + (Vector A,Vector B){
        return Vector(A.x + B.x , A.y + B.y);
    }
    Vector operator - (Vector A,Vector B){
        return Vector(A.x - B.x , 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);
    }


/*
bool operator < (const Point&a , const Point&b){

}
*/
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)); //求出cos ,再用acos求出角度、
}

double Cross(Vector A , Vector B){ //求叉积
    return A.x*B.y - A.y* B.x;
}
double Area2(Point A,Point B,Point C){
    return Cross(B-A,C-A);
}
//向量旋转 公式 x' = x * cosa - y * sina, y' = x * sina + y * cosa;
Vector Rotate(Vector A,double rad){
    return Vector(A.x * cos(rad) - A.y*sin(rad), A.x*sin(rad) + A.y * cos(rad));
}
//计算向量的 单位 法线。
Vector Normal(Vector A){
    double L = Length(A);
    return Vector(-A.y / L , A.x /L);
}
//计算交点, 调用前确保 Cross(v,w) 非0
//设 直线分别为 P + tv 和 Q + tw;
Point GetLineIntersection(Point P,Vector v,Point Q,Vector w){
    Vector u = P-Q;
    double t = Cross( w , u) / Cross( v , w );
    return P + v * t;
}

//点到直线距离
double DistanceToLine(Point P, Point A,Point B){ //叉积 除以 底
    Vector v1 = B - A, v2 = P - A;
    return fabs(Cross(v1,v2)) / Length(v1); //不取绝对值,则为有向距离
}
//点到线段的距离

double DistanceToSegment(Point P, Point A, Point B){
    if(A == B) return Length(P - A) ; // AB重合,成点对点长度
    Vector v1 = B - A, v2 = P - A, v3 = P - B;
    if(dcmp(Dot(v1,v2)) < 0) return Length(v2); // == 0 的时候是垂直的,小于零在二三象限; 即离A近;
    else if(dcmp(Dot(v1,v2)) > 0) return Length(v3);  //大于零 一四象限。
    else return fabs(Cross(v1,v2)) / Length(v1); // 垂直的情况,直接用叉积来求了。
}

Point GetLineProjection(Point P,Point A,Point B){ //获得P在线段AB上投影的节点。
    // AB向量  A + tv , Q 即投影点 A + t0v ,
    // PQ 垂直于AB ,Dot()应该为0. 所以 Dot(v , P - (A + t0v))'
    // 分配率  Dot(v , P - A) - t0 * Dot(v,v) = 0;
    Vector v = B - A;
    return A + v * (Dot(v , P - A) / Dot(v,v));
}
//判断线段相交
// 规范相交 : 两线段恰好有一个公共点。且不在端点。
// 充要条件: 每条线段两个端点都在另一条线段的两侧。(叉积符号不同)
bool SegmentProperIntersection(Point a1, Point a2,Point b1,Point b2){
    double c1 = Cross(a2-a1 , b1 -a1) , c2 = Cross(a2-a1 , b2 -a1) ;
    double c3 = Cross(b2-b1 , a1 -b1) , c2 = Cross(b2-b1 , a2 -b1) ;
    return dcmp(c1) * dcmp(c2) < 0 && dcmp(c3) * dcmp(c4) < 0 ;
}<span style="display: none; width: 0px; height: 0px;" id="transmark"></span>
//判断点p是否在线段a1a2上
bool OnSegment(Point p,Point a1,Point a2)
{
    return dcmp(Cross(a1-p,a2-p))==0&&dcmp(Dot(a1-p,a2-p))<0;
}


Point getD(Point A, Point B, Point C){ // A B C 逆时针给出
    Vector v1 = C - B;
    double a1 = Angle(A - B , v1);
    v1 = Rotate(v1, a1 / 3);

    Vector v2 = B - C;
    double a2 = Angle(A-C,v2);
    v2 = Rotate(v2 , -a2 / 3);

    return  GetLineIntersection(B,v1,C,v2);
}

Point read_Point(){
    Point tmp;
     scanf("%lf%lf",&tmp.x,&tmp.y);
     return tmp;
}
int main(){
    int T;
    Point A,B,C,D,E,F;
    scanf("%d",&T);
    while(T--){
        A = read_Point();
        B = read_Point();
        C = read_Point();
        D = getD(A ,B, C) ; //逆时针给出,
        E = getD(B ,C, A) ;
        F = getD(C ,A, B) ;
        printf("%.6f %.6f %.6f %.6f %.6f %.6f\n",D.x,D.y,E.x,E.y,F.x,F.y);
    }
    return 0 ;
}
</pre><p></p><pre code_snippet_id="1614361" snippet_file_name="blog_20161021_21_2365810" name="code" class="cpp">//约数枚举O(sqrt(n))
vector<int> divisor(int n){
    vector<int>res;
    for(int i=1;i*i <=n;i++){
        if(n % i ==0){
            res.push_back(i);
            if(i!= n/i)
                res.push_back(n/i);
        }
    }
    return res;
}
const int maxn = 10000000 + 10;
bool isprime[maxn];
int prime[maxn];int cnt = 0;
void Prime(){
    prime[2] = 0; cnt = 0;
    for(int i=2;i<maxn;i++){
        if(!isprime[i]){
            prime[cnt++] = i;
            for(int j=i*2;j<maxn;j+=i){
                isprime[j] = 1;
            }
        }
    }
}


最长回文的Manchester算法

#include <iostream>  
#include <cstdio>  
#include <cstring>  
#include <cmath>  
#include <algorithm>  
using namespace std;  
typedef long long ll;  
const int maxn = 110010;  
char s[maxn];  
char s2[maxn*2];  
int p[maxn *2]; // mx == p[id] + id , 回文右边界  
// id 回文中心  
void Man(){  
    memset(p,0,sizeof(p));  
    int mx = 0 ,id=0;  
    for(int i=0;s2[i]!='\0';i++){  
        p[i] = mx > i ?min(p[2*id-i],mx-i ):1;  
        while(s2[i+p[i]] == s2[i-p[i]]) p[i]++;  
        if(p[i] + i > mx){  
            mx = p[i] + i;  
            id = i;  
        }  
    }  
}  
int main(){  
    while(scanf("%s",s)!=EOF){  
        s2[0] = '$';  
        int len = strlen(s);  
        int c = 1;//注意这里 == 1  
        for(int i=0;i<len;i++){  
            s2[c++] = '#';  
            s2[c++] = s[i];  
        }  
        s2[c++] ='#';  
        s2[c] = '\0';  
        Man();  
        int ans = 1;  
        for(int i=0;i<c;i++)  
            ans = max(ans,p[i]);  
        printf("%d\n",ans-1);  
    }  
    return 0;  
}  


卡特兰数递推公式:

h(n)=h(n-1)*(4*n-2)/(n+1)




小模块整理

ll strToll(string tmp){
    int len = tmp.length();
    //cout<<len<<"jj"<<endl;
    ll ans = 0;ll cc = 1;
    for(int i=len-1;i>=0;i--){
        ans += (tmp[i]-'0') * cc;
        cc*=10;
    }
    return ans;
}



  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值