Algorithm template or conclusion

Posted by groundwar on Fri, 28 Jan 2022 20:45:07 +0100

explain

1. The efficiency of all the following algorithms shows that most of them are measured by themselves or through OJ on the network
2. Some (about 80%) codes come from OJ of other bloggers or networks
3. Update as soon as you think of it
4. It is applicable to xcpc, blue bridge and other algorithm competitions
5. I'm a konjaku, whining, please spray orz

Mathematical algorithm

Maximum common factor gcd

1. STL is ready-made and should be adjusted directly

#include <algorithm>
__gcd(a,b);//Both int and long can be used

2. Speed and__ gcd(x,y) is comparable

inline int gcd(int a,int b) {//Bit operation optimization is used, and inline constant level optimization can not be written
	if(b) while((a%=b) && (b%=a));
	return a+b;
}

3. The iterative version is a little slower than 1 and 2

inline int gcd(int a,int b){
  int tem;
	    while(b){
			tem=a;
			a=b;
			b=tem%b;
	    }
	    return a;
	}

4. The most conventional recursive version is slower than 1,2,3

inline int gcd(int a,int b){
    if(!b)return a;
    return gcd(b,a%b);
}

Least common multiple

	Just remember this formula:
		(a,b Least common multiple of)*(a,b Maximum common factor of)=a*b;

Single and linear prime numbers

Version 1, fast and easy to RE

bool pri[MAXN];//This should be made into a global variable
void prime(int x){	//It can be written as int & X according to the actual situation
	 int i,j;		//After all, it takes time
	    for(i=2;i*i<=x;i++){
		if(!pri[i]){
		    for(j=i<<1;j<=x;j+=i)	//Pay attention to the data range. If i is too large, it will RE. i < < 1 here is equivalent to i*2
			if(!pri[j])	//After testing, it is faster than direct assignment pri[j]=1
			   pri[j]=1;
			}
	    }
	}

Version 2, stable, recommended

bool pri[MAXN];//This should be made into a global variable
void prime(int x){	//It can be written as int & X according to the actual situation
   	int i,j,k;		//After all, it takes time
   	for(i=2;i*i<=x;i++){
	if(!pri[i]){
	    k=x/i;
	    for(j=2;j<=k;j++)
			if(!pri[j*i])	//After testing, it is faster than direct assignment pri[i*j]=1
		   		pri[j*i]=1;
			}
    }
}

Fast power 𞓜 remainder operation

Remainder operation:Although the data is int Range,But it is strongly recommended to open it long long because mo Big will really explode
 Counting :Take out mod take off,Look at this range, you can consider using it int
inline long long fastpower(long long base,long long power,long long mo){
	long long result=1;
	base%=mo;
	while(power>0){
		if(power & 1){	//This is equivalent to if(power%2==1)
			result=(result*base)%mo;
		}
		base=(base*base)%mo;
		power>>=1;
	}
	return result%mo;//To be on the safe side, I'll take the rest again. I've really stuck with some questions
}

search algorithm

DFS

BFS

Dichotomy

Bidirectional BFS

A*

dynamic programming

knapsack problem

I didn't take notes. I'll do it later

01 Backpack

Multiple Backpack

Complete Backpack

Group Backpack

Multi group knapsack

Fully grouped Backpack

Subsequence

LCS

Space complexity of the ultimate optimized version (n) time complexity (m*n)

char a[MAXN];
char b[MAXN];
int len_a,len_b;
int tem,pre;
int dp[MAXN];

int main(){
    scanf("%s",a+1);
    scanf("%s",b+1);
    len_a=strlen(a+1);
    len_b=strlen(b+1);
    for(int i=1;i<=len_a;i++){
        tem=0;
        for(int j=1;j<=len_b;j++){
            pre=tem;
            tem=dp[j];
            if(a[i]==b[j]){
                dp[j]=pre+1;
            }else{
                dp[j]=max(dp[j],dp[j-1]);
            }
        }
    }
    printf("%d",dp[len_b]);
    return 0;
}

LIS

Time complexity of the ultimate version (n*log(n))

int n,a;
int dp[100005];
int ans;

int main(){
    cin>>n;
    for(int i=0;i<n;i++){
		cin>>a;
		if(a>dp[ans]){
		    dp[++ans]=a;
		}else if(a<dp[ans]){
		    dp[lower_bound(dp+1,dp+ans+1,a)-dp]=a;
		}
    }
    cout<<ans;
    return 0;
}

LCIS

Not yet

Various dp

Not yet, tearful eyes

character string

String matching algorithm

KMP

Time complexity (m+n)

char a[MAXSIZE],b[MAXSIZE];
int next[MAXSIZE];
int n,m;

void inita(){//Find the same Prefix suffix table of prefixes
    next[0]=-1;
    next[1]=0;
    int len=0,i=1;
    while(i<m-1){
		if(len==-1 ||b[i]==b[len]){
		    next[++i]=++len;
		}else{
		    len=next[len];
		}
    }
}

void kmp(){
    inita();
    int i=0,len=0;
    while(i<n){
		if(len==m-1 && a[i]==b[len]){
		    len=next[len];
		}
		if(len==-1 || a[i]==b[len]){
		    len++;
		    i++;
		}else{
		    len=next[len];
		}
    }
}

Hash retrieval

Theoretical time complexity (m+n),B is a prime number, which is taken at random. The hash algorithm is not 100% accurate, and there is a certain probability of error
(of course, we can also use the simple double method to test again when the hash value is the same, so as to achieve 100% matching accuracy)
In most cases, the speed of hash retrieval is very fast
In fact, you can also write double and triple hashes. The idea is similar. I won't write them here for the time being

The scrolling hash I wrote here has a swish time complexity (m+n)

int B=7;//A prime number
void hash_pipei(){
	if(m>n)     // m is the length of a string and n is the length of b string
		return;
	for(int i=0;i<m;i++){
		hash_b=hash_b*B+b[i];
		t*=B;
	}
	for(int i=0;i<m;i++){
		hash_a=hash_a*B+a[i];
	}
	
	if(hash_a==hash_b)
		printf("YES\n");
	
	for(int i=m;i<n;i++){
		hash_a=hash_a*B-t*a[i-m]+a[i];
		if(hash_a==hash_b)
		 	printf("YES\n");
	}
}

Query substring hash with time complexity (1)

long long hash_num[MAXN];//All prefix hash values
char s[MAXN];

void hash_val(){
   int base=7;
    Bi[0]=1;
    for(int i=1;i<n;i++){
		Bi[i]=Bi[i-1]*base;
    }
    hash_num[0]=s[0];
    for(int i=1;i<n;i++){
		hash_num[i]=hash_num[i-1]*base+s[i];
    }
}

ull hash_LR(int L,int R){//Calculate the hash value of the given interval
    return hash_num[R]-hash_num[L-1]*Bi[R-L+1];
}

Dictionary tree

Website OI Wiki, this code is really OK. I can borrow it

struct trie {
  int nex[100000][26], cnt;
  bool exist[100000];  // Does the string at the end of this node exist

  void insert(char *s, int l) {  // Insert string
    int p = 0;
    for (int i = 0; i < l; i++) {
      int c = s[i] - 'a';
      if (!nex[p][c]) nex[p][c] = ++cnt;  // If not, add nodes
      p = nex[p][c];
    }
    exist[p] = 1;
  }
  bool find(char *s, int l) {  // Find string
    int p = 0;
    for (int i = 0; i < l; i++) {
      int c = s[i] - 'a';
      if (!nex[p][c]) return 0;
      p = nex[p][c];
    }
    return exist[p];
  }
};

AC automata

Not yet

aggregate

Joint search set

And search the set (non rank optimization) / / note that the first bit I write cannot have 0, because my obsessive-compulsive disorder makes me don't want to initialize

int fa[1005];//global variable
inline int find(int &u){
    if ( 0==fa[u]) return fa[u]=u;
    int x=u;
    while(x!=fa[x]) x=fa[x];
    return fa[u]=x;
}
inline void un(int u,int v){
    fa[find(u)]=find(v);
}
inline bool same_r(int u,int v){
    return find(u)==find(v);
}

rank optimized version, no notes, I'll fill it up later

graph theory

shortest path

I didn't take notes after learning. Er, I'll learn more when I have time

minimum spanning tree

Kruskal algorithm

#include<bits/stdc++.h>
using namespace std;
int fa[5005];
inline int find(int &u){
    if ( 0==fa[u]) return fa[u]=u;
    int x=u;
    while(x!=fa[x]) x=fa[x];
    return fa[u]=x;
}
inline void un(int u,int v){
    fa[find(u)]=find(v);
}
inline bool same_r(int u,int v){
    return find(u)==find(v);
}
struct cpp{
    int a,b,c;
}edge[200005];
bool cmp(cpp &x,cpp &y){
    return x.c<y.c;
}
int ans;
int n,m;

int main(){
    scanf("%d %d",&n,&m);
    for(int i=0;i<m;i++)
	scanf("%d %d %d",&edge[i].a,&edge[i].b,&edge[i].c);
    sort(edge,edge+m,cmp);
    for(int i=0;i<m;i++){
		if(same_r(edge[i].a,edge[i].b))
		    continue;
		un(edge[i].a,edge[i].b);
		ans+=edge[i].c;
    }
    cout<<ans;//Output minimum cost
    return 0;
}

Prim algorithm

It's badly written. Change it when you have time, or borrow it from other bloggers

struct cpp{
	int x,cost;
}tem;
vector<cpp> g[5005];
bool vis[5005];
int num=1;
int dis[5005];
int n,m;

inline int prim(){
    int sum=0,min_cost,cnt=0;
    while(++cnt<n){
		min_cost=2e9;
		for(unsigned int i=0;i<g[num].size();i++){
		    dis[g[num][i].x]=min(dis[g[num][i].x],g[num][i].cost);
		}
		vis[num]=1;
		for(int i=1;i<=n;i++){
    		if(vis[i]==0 && min_cost>dis[i]){
				num=i;
				min_cost=dis[i];
    		}
		}
		sum+=min_cost;
    }
    return sum;
}

int main(){
    cin>>n>>m;
    for(int i=2;i<=n;i++)
		dis[i]=2e9;
    for(int i=0,a;i<m;i++){
		cin>>a>>tem.x>>tem.cost;
		g[a].push_back(tem);
		swap(a,tem.x);
		g[a].push_back(tem);
    }
    cout<<prim();
    return 0;
}

Priority queue optimization n*log(n) (I wrote it slower, busi)
Don't put it up for the time being

Constant optimization

Read quickly

void read(int& x) {//Here is int or long
	int f = 1; x = 0;
   	char ch = getchar();
   	while (ch < '0' || ch > '9')   {if (ch == '-') f = -1; ch = getchar();}
	while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
   	x *= f;
}

Topics: Algorithm XCPC