常用模板总结(持续更新)
【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); //返回字典序最小的下标
}

浙公网安备 33010602011771号