版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40758751/article/details/82810357
1.数学
1.1素数
1.1.1素数筛法(欧拉筛法,判断<maxn的数是否是素数及求取<maxn的素数)
/*
*notprime是一张表,false表示是素数,true表示不是素数
*prime是素数表,储存小于maxn的全部素数。
*/
const int maxn = 10500000;
int prime[maxn];
bool notprime[maxn];
int Euler(int _n) //欧拉筛法求素数,时间复杂度为O(n)。
{
int cnt = 0;
memset(notprime, 0, sizeof notprime);
memset(prime, 0, sizeof prime);
for (int i = 2; i <= _n; i++)
{
if(!notprime[i])
prime[cnt++] = i;
for (int j = 0; j < cnt && i*prime[j] <= _n; j++)
{
notprime[i*prime[j]] = true;
if (i % prime[j] == 0) break;
}
}
return cnt;
}
1.1.2素数筛法(埃氏筛法,判断<maxn的数是否是素数及求取<maxn的素数)
/*
*notprime是一张表,false表示是素数,true表示不是素数
*prime是素数表,储存小于maxn的全部素数。
*/
const int maxn = 10500000;
int prime[maxn];
bool notprime[maxn];
int Eratosthenes(int _n) //埃拉托斯特尼筛法,时间复杂度为O(nloglogn).
{
int cnt = 0;
memset(notprime, 0, sizeof notprime);
memset(prime, 0, sizeof prime);
for(int i = 2; i <= _n; i++)
{
if(!notprime[i])
{
prime[cnt++] = i;
for (int j = i+i; j <= _n; j += i)
{
notprime[j] = true;
}
}
}
return cnt;
}
1.2最大公约数
int gcd(int big, int small)
{
if (small > big) swap(big, small);
int temp;
while (small != 0){ // 辗转相除法
if (small > big) swap(big, small);
temp = big % small;
big = small;
small = temp;
}
return big;
}
1.3快速幂
1.3.1普通快速幂
int power(long long a, int n)
{
long long ans = 1;
while(n > 0) {
if(n&1) {
ans *= a;
ans %= mod;
}
a *= a%mod;
a %= mod;
n /= 2;
}
return ans%mod;
}
1.3.2矩阵快速幂
书上
2.图论
2.1最短路
2.1.1Dijkstra单源最短路
权值非负
int n, m, s, t;
int len;
struct road
{
int u, v, cost;
int next;
};
struct node
{
int v;
int len;
int cost;
node(int v, int l, int c):v(v),len(l),cost(c){}
friend bool operator <(node a, node b)
{
return a.cost>b.cost;
}
};
road G[maxn*5];
int head[maxn];
int dist[maxn];
bool vis[maxn];
void addroad(int u, int v, int cost)//加边
{
G[len].u = u;
G[len].v = v;
G[len].cost = cost;
G[len].next = head[u];
head[u] = len++;
}
void dij()
{
fill(dist, dist+n+1, INF);
dist[1] = 0;
priority_queue<node> pque;
pque.push(node(1,0));
while(pque.size())
{
node p = pque.top(); pque.pop();
int v = p.v;
if(dist[v] < p.cost) continue;
for(int i = head[v]; i!=-1; i = G[i].next)
{
road e = G[i];
if(dist[e.v] > min(dist[e.v],max(dist[e.u], e.cost)))
{
dist[e.v] = min(dist[e.v],max(dist[e.u], e.cost));
pque.push(node(e.v, dist[e.v] ) );
}
}
}
}
2.1.2Bellman—Ford判环
int n, m, s, t;
int len;
struct road
{
int u, v, cost;
int next;
};
struct node
{
int v;
int len;
int cost;
node(int v, int l, int c):v(v),len(l),cost(c){}
friend bool operator <(node a, node b)
{
return a.cost>b.cost;
}
};
road G[maxn*5];
int head[maxn];
int dist[maxn];
bool vis[maxn];
void addroad(int u, int v, int cost)
{
G[len].u = u;
G[len].v = v;
G[len].cost = cost;
G[len].next = head[u];
head[u] = len++;
}
int bellman_ford()
{
int res;
fill(dist, dist+n+1, INF);
dist[1] = 0;
for(int i = 0; i < n; i++)
{
for(int k = 0; k < len; k++)
{
road e = G[k];
if(dist[e.v] > dist[e.u] + e.cost)
{
dist[e.v] = dist[e.u] + e.cost;
if(i == n-1)
{
return 0;
}
}
}
}
return 1;
}
2.1.3Floyd多源最短路
int G[maxn][maxn];//储存e(i,j)的权值,不存在边时设为INF,其中G[i][i]==0
void floyd()
{
for(int k = 0; k <= mx; k++)
{
for(int i = 0; i <= mx; i++)
{
for(int j = 0; j <= mx; j++)
{
G[i][j] = min(G[i][j], G[i][k] + G[k][j]);
}
}
}
}
2.1.4次短路算法
int n, m, s, t;
int len;
struct road
{
int u, v;
int next;
int cost;
};
struct node
{
int v;
int cost;
node(int v, int c):v(v),cost(c){}
friend bool operator <(node a, node b)
{
return a.cost>b.cost;
}
};
road G[200500];
int head[maxn];
int dist[maxn];
int dist2[maxn];
void dij()
{
fill(dist2, dist2+n+1,INF);
fill(dist, dist+n+1,INF);
dist[1] = 0;
priority_queue<node> pque;
pque.push(node(1, 0));
while(pque.size())
{
node p = pque.top();pque.pop();
int v = p.v;
//if(dist2[v] < p.cost) continue;
for(int i = head[v]; i != -1; i=G[i].next)
{
road e = G[i];
int d = p.cost + e.cost;
if(dist[e.v] > d)
{
swap(dist[e.v], d);
pque.push(node(e.v, dist[e.v]));
}
if(dist2[e.v] > d && d > dist[e.v])
{
dist2[e.v] = d;
pque.push(node(e.v, dist2[e.v]));
}
}
}
}
2.1.5双权值求花费
/*
*注意:在本模板中 len表示路长,cost表示花费。
*/
int n, m, s, t;
int len;
struct road
{
int u, v, len, cost;
int next;
};
struct node
{
int v;
int len;
int cost;
node(int v, int l, int c):v(v),len(l),cost(c){}
friend bool operator <(node a, node b)
{
if(a.len == b.len)
return a.cost>b.cost;
return a.len>b.len;
}
};
road G[maxn*5];
int head[maxn];
int mx = -INF;
int dist[maxn];
int cost[maxn];
int path[maxn];
void addroad(int u, int v, int l, int cost)
{
G[len].u = u;
G[len].v = v;
G[len].len = l;
G[len].cost = cost;
G[len].next = head[u];
head[u] = len++;
}
int dij()
{
int res = 0;
fill(dist, dist+n+1, INF);
fill(path, path+n+1, -1);
fill(cost, cost+n+1, 0);
dist[1] = 0;
priority_queue<node> pque;
pque.push(node(1, 0, 0));
while(pque.size())
{
node p = pque.top(); pque.pop();
int v = p.v;
if(dist[v] < p.len) continue;
for(int i = head[v]; i != -1; i = G[i].next)
{
road e = G[i];
if(dist[e.v] > dist[e.u] + e.len)
{
dist[e.v] = dist[e.u] + e.len;
cost[e.v] = cost[e.u] + e.cost;
path[e.v] = i;
pque.push(node(e.v, dist[e.v], cost[e.v]));
}
else if(dist[e.v] == dist[e.u] + e.len)
{
if(path[e.v] != -1 && G[path[e.v]].cost > e.cost)
{
path[e.v] = i;
pque.push(node(e.v, dist[e.v], cost[e.v]));
}
}
}
}
for(int i = 1; i <= n; i++)
{
if(path[i]!=-1)
{
res += G[path[i]].cost;
}
}
return res;
}
2.2最小(大)生成树
2.2.1Prim算法
int n, m, s, t;
int road[maxn][maxn];//储存e(i,j)的权值,不存的边设为INF
bool vis[maxn];//标记是否属于集合X
int dist[maxn];//从集合X出发到每个顶点最小距离
int prim()
{
memset(vis, 0, sizeof vis);
fill(dist, dist+maxn, INF);
dist[1] = 0;
int res = 0;
while(1)
{
int v = -1;
//从不属于X的定点中取出从距X最近的定点
for(int i = 1; i <= n; i++)
{
if(!vis[i] &&(v==-1|| dist[i] < dist[v])) v = i;
}
if(v == -1) break;
vis[v] = true;//把顶点v加入X
res += dist[v];//更新结果
for(int i = 1; i <= n; i++)
{
dist[i] = min(dist[i], road[v][i]);//更新dist数组
}
}
return res;
}
2.2.2Kruskal算法
int n, m, s, t;
int len;
struct road
{
int u, v, cost;
};
road G[maxn*5];
int par[maxn<<1];
void init()
{
for(int i = 0; i < maxn<<1; i++) par[i] = i;
}
int Find(int x)
{
return par[x]==x? x : par[x] = Find(par[x]);
}
bool same(int x, int y)
{
int fx = Find(x), fy = Find(y);
if(fx == fy)return true;
else return false;
}
void unite(int x, int y)
{
int fx = Find(x), fy = Find(y);
if(fx == fy) return;
else{
par[fx] = fy;
return;
}
}
bool cmp(road a, road b)
{
return a.cost>b.cost;
}
int kruskal()
{
sort(G, G+len, cmp);
init();
int res = 0;
for(int i = 0; i < len; i++)
{
road e = G[i];
if(!same(e.u, e.v))
{
unite(e.u, e.v);
res+=e.cost;
}
}
return res;
}
2.3强连通分量
2.3.1Tarjan算法
int n, m;
struct edge
{
int u, v;
int next;
};
edge G[maxn<<3];
int h[maxn];
int dfn[maxn];
int low[maxn];
int color[maxn];
bool vis[maxn];
int tot, len, out, sum;
stack<int> sta;
void init()
{
fill(h, h+maxn, -1);
fill(dfn, dfn+maxn, 0);
fill(vis, vis+maxn, 0);
fill(isout, isout+maxn, 0);
fill(color, color+maxn, 0);
tot = 0;
len = 0;
sum = 0;
out = 0;
}
void tarjan(int u)
{
dfn[u] = low[u] = ++tot;
vis[u] = true;
sta.push(u);
for(int i = h[u]; ~i; i = G[i].next)
{
edge e = G[i];
if(!dfn[e.v])
{
tarjan(e.v);
low[u] = min(low[u], low[e.v]);
}
else if(vis[e.v])
{
low[u] = min(low[u], dfn[e.v]);
}
}
if(dfn[u] == low[u])
{
int x;
++sum;
do
{
x = sta.top(); sta.pop();
vis[x] = false;
color[x] = sum;
}
while(x != u);
}
}
2.3.2 Kosaraju算法(解决2-SAT问题)
int n, m;
vector<int> G[maxn];
vector<int> rG[maxn];
vector<int> vs;
bool used[maxn];
int cmp[maxn];
int s[maxn], t[maxn], d[maxn];
void add_edge(int from, int to)
{
G[from].pb(to);
rG[to].pb(from);
}
void dfs(int v)
{
used[v] = true;
for(int i = 0; i < G[v].size(); i++)
{
if(!used[G[v][i]])
dfs(G[v][i]);
}
vs.pb(v);
}
void rdfs(int v, int k)
{
used[v] = true;
cmp[v] = k;
for(int i = 0; i < rG[v].size(); i++)
{
if(!used[rG[v][i]])
rdfs(rG[v][i], k);
}
}
int ssc()
{
memset(used, 0, sizeof used);
for(int i = 0; i < n<<1; i++)
{
if(!used[i])
dfs(i);
}
memset(used, 0, sizeof used);
int k = 0;
for(int i = vs.size()-1; i >= 0; i--)
{
if(!used[vs[i]])
rdfs(vs[i], k++);
}
return k;
}
/*
*如果需要输出结果,变量i为真满足的条件为cmp[i]>cmp[i+n],否则i为假
*/
3.数据结构
3.1线段树
3.1.1单点更新的线段树
int n, m, t, _n;
int dat[maxn<<2];
void build(int root, int left, int right)
{
if(left == right)
{
dat[root] = 1;
return;
}
int mid, rt;
mid = (left+right)>>1;
rt = root<<1;
build(rt, left, mid);
build(rt|1, mid+1, right);
dat[root] = dat[rt] + dat[rt|1];
}
void Update(int pos, int val, int root, int left, int right)
{
if(left==right)
{
dat[root] = val;
return;
}
int m=(left+right)>>1;
if(pos <= m) Update(pos, val, root<<1, left, m);
else Update(pos, val, root<<1|1, m+1, right);
dat[root] = dat[root<<1] + dat[root<<1|1];
}
int query(int qleft, int qright, int root, int left, int right)
{
if(qleft<=left && right<=qright)
{
return dat[root];
}
int m = (left+right)>>1;
int ans = 0;
if(qleft <= m ) ans += query(qleft, qright, root<<1, left, m);
if(qright > m) ans += query(qleft, qright, root<<1|1, m+1, right);
return ans;
}
3.1.2区间更新的线段树
int n, m, t, _n;
struct node
{
long long num;
long long lazy;
};
node dat[maxn<<2];
long long arr[maxn];
void build(int k, int l, int r)
{
if(l==r)
{
dat[k].num = arr[l];
dat[k].lazy = 0;
return;
}
build(k<<1, l, (l+r)/2);
build(k<<1|1, (l+r)/2+1, r);
dat[k].num = dat[k<<1].num + dat[k<<1|1].num;
}
void update(int a, int b, long long val, int k, int l, int r)//区间加减
{
if(r<a || b<l) return;
if(a<=l && r<=b)
{
dat[k].lazy += val;
dat[k].num += (val*(r-l+1));
return;
}
if(dat[k].lazy)
{
dat[k<<1].num += ((l+r)/2-l+1)*dat[k].lazy;
dat[k<<1].lazy += dat[k].lazy;
dat[k<<1|1].num += (r-(l+r)/2)*dat[k].lazy;
dat[k<<1|1].lazy += dat[k].lazy;
dat[k].lazy = 0;
}
update(a,b,val,k<<1,l,(l+r)/2);
update(a,b,val,k<<1|1,(l+r)/2+1,r);
dat[k].num = dat[k<<1].num + dat[k<<1|1].num;
}
long long query(int a, int b, int k, int l, int r)
{
if(a<=l && r<=b)
return dat[k].num;
if(dat[k].lazy)
{
dat[k<<1].num += ((l+r)/2-l+1)*dat[k].lazy;
dat[k<<1].lazy += dat[k].lazy;
dat[k<<1|1].num += (r-(l+r)/2)*dat[k].lazy;
dat[k<<1|1].lazy += dat[k].lazy;
dat[k].lazy = 0;
}
int m = (l+r)/2;
long long ans = 0;
if(a<=m) ans+=query(a,b,k<<1,l,m);
if(b>m) ans+=query(a,b,k<<1|1,m+1,r);
return ans;
}
3.2二维树状数组
int n, w, h, s, t;
int bit[maxn][maxn];
int lowbit(int x)
{
return x&(-x);
}
void add(int x, int y, int v)
{
for(int i = x; i <= h; i+=lowbit(i))
{
for(int j = y; j <= w; j+=lowbit(j))
{
bit[i][j] += v;
}
}
}
int query(int x, int y)
{
int res = 0;
for(int i = x; i; i-=lowbit(i))
{
for(int j = y; j; j-=lowbit(j))
{
res+=bit[i][j];
}
}
return res;
}
4.字符串处理
4.1KMP算法
//未改进的KMP算法代码实现
void get_next(int *next, char *T, int len)
{
next[0] = -1;//-1代表没有重复子串
int k = -1;
for (int q = 1; q <= len; q++)
{
while (k > -1 && T[k+1] != T[q])//下一个元素不相等,把k向前回溯
{
k = next[k];
}
if (T[k+1] == T[q])//下一个元素相等,所以最长重复子串+1
{
k = k+1;
}
next[q] = k;//给next数组赋值
}
}
int KMP(char *s, int len, char *p, int plen)//利用KMP算法匹配
{
int *next = new int(plen);
get_next(next, p, plen);
int k = -1;
int i = 0;
for (; i < len; i++)
{
while (k > -1 && p[k+1]!=s[i])//两串下一个字符不相等,向前回溯(效率高就是在这里,每次匹配失败,
//k不用直接变为0,从第一个字符开始重新匹配,而是变为最长重复子串的下一个字符,从中间开始匹配即可)。
{
k = next[k];
}
if(p[k+1] == s[i])//两个串的字符相等,k+1来匹配子串的一个字符
{
k++;
}
if (k == plen-1)//匹配成功,返回短串在长串的位置。
{
return i-plen+1;
}
}
return -1;
}
4.2Manacher算法
/*
* 求最长回文子串
*/
const int MAXN=110010;
char Ma[MAXN*2];
int Mp[MAXN*2];
void Manacher(char s[],int len){
int l=0;
Ma[l++]='$';
Ma[l++]='#';
for(int i=0;i<len;i++){
Ma[l++]=s[i];
Ma[l++]='#';
}
Ma[l]=0;
int mx=0,id=0;
for(int i=0;i<l;i++){
Mp[i]=mx>i?min(Mp[2*id−i],mx−i):1;
while(Ma[i+Mp[i]]==Ma[i−Mp[i]])Mp[i]++;
if(i+Mp[i]>mx){
mx=i+Mp[i];
id=i;
}
}
}
/*
* abaaba
* i: 0 1 2 3 4 5 6 7 8 9 10 11 12 13
* Ma[i]: $ # a # b # a # a # b # a #
* Mp[i]: 1 1 2 1 4 1 2 7 2 1 4 1 2 1
*/
char s[MAXN];
int main(){
while(scanf("%s",s)==1){
int len=strlen(s);
Manacher(s,len);
int ans=0;
for(int i=0;i<2*len+2;i++)
ans=max(ans,Mp[i]−1);
printf("%d\n",ans);
}
return 0;
}
5.搜索
5.1广搜
int move[4][2] = {1,0,0,1,-1,0,0,-1};//遍历四个方向
struct node
{
int x, y, step;//x,y是坐标,t是步数.
node(int _x, int _y, int _step){x = _x; y= _y; step=_step;}
node(){}
};
int h, w, sx, sy, gx, gy;
int map[500][500];
bool visit[500][500];
int bfs()
{
memset(visit, 0, sizeof(visit));
queue<node> que;//建立空队列
node cor(sx,sy,0); //压入起点
que.push(cor);
while (!que.empty())
{
node next = que.front();//下一个队列元素
que.pop();//出队
for (int i = 0; i < 4; i++)
{
int nx = cor.x+move[i][0], ny = cor.y+move[i][1];
if (0<=nx&&0<=ny&&nx<h&&ny<w&&!visit[nx][ny]) //保证新元素不越界并且没有访问过
{
visit[nx][ny] = true;
que.push(node(nx,ny,next.step+1));
if (nx == gx&& ny == gy)//满足条件结束函数
{
return next.step+1;
}
}
}
}
return -1;
}
5.2二分查找
/*
|二分搜索|
|要求:先排序|
*/
// l为最开始元素, r是末尾元素,x是要找的数
int bsearch(int *A, int l, int r, int val){
int m;
while (l < r){
if(l==r)
{
if(A[l] == val)
return l;
else
return -1;
}
m = (l + r) / 2;
if (A[m] >= val) r = m; else l = m + 1;
}
return -1;
}
/*
最后l == r
如果找有多少的x,可以用lower_bound查找一遍,upper_bound查找一遍,下标相减
C++自带的lower_bound(a,a+n,x)返回数组中最后一个x的下一个数的地址
upper_bound(a,a+n,x)返回数组中第一个x的地址
如果a+n内没有找到x或x的下一个地址,返回a+n的地址
lower_bound(a,a+n,x)-upper_bound(a,a+n,x)返回数组中x的个数
*/
6.其他
6.1头文件及宏定义
#include<bits/stdc++.h>
#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <malloc.h>
#include <iostream>
#include <algorithm>
#include <functional>
#define sdddd(x,y,z,k) scanf("%d%d%d%d", &x, &y, &z, &k)
#define sddd(x,y,z) scanf("%d%d%d", &x, &y, &z)
#define sdd(x,y) scanf("%d%d", &x, &y)
#define sd(x) scanf("%d", &x)
#define mp make_pair
#define pb push_back
#define lson k<<1
#define rson k<<1|1
#define mid (1+r)/2
#define ms(x, y) memset(x, y, sizeof x)
#define MOD 142857
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1000050;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
6.2输入输出加速
std::ios::sync_with_stdio(false);
6.3文件输入输出
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
6.4STL库
6.4.1set及multiset
//set及multiset用法(后者允许重复)
//主要函数:
begin() //返回指向第一个元素的迭代器
clear() //清除所有元素
count() //返回某个值元素的个数
empty() //如果集合为空,返回true
end() //返回指向最后一个元素的迭代器
erase() //删除集合中的元素(参数是一个元素值,或者迭代器)
find() //返回一个指向被查找到元素的迭代器
insert() //在集合中插入元素
size() //集合中元素的数目
lower_bound() //返回指向大于(或等于)某值的第一个元素的迭代器
upper_bound() //返回大于某个值元素的迭代器
equal_range() //返回集合中与给定值相等的上下限的两个迭代器
//(注意对于multiset 删除操作之间删除值会把所以这个值的都删掉,删除一个要用迭代器)
6.4.2map
begin() //返回指向map头部的迭代器
clear()// 删除所有元素
count()// 返回指定元素出现的次数
empty() //如果map为空则返回true
end() //返回指向map末尾的迭代器
equal_range()// 返回特殊条目的迭代器对
erase() //删除一个元素
find() //查找一个元素
insert() //插入元素
lower_bound() //返回键值>=给定元素的第一个位置
max_size() //返回可以容纳的最大元素个数
rbegin() //返回一个指向map尾部的逆向迭代器
rend() //返回一个指向map头部的逆向迭代器
size() //返回map中元素的个数
swap()// 交换两个map
upper_bound()// 返回键值>给定元素的第一个位置
value_comp() //返回比较元素value的函数
for(auto i = mp.begin(); i != mp.end(); i++)//遍历,i为pair类型 访问用'.'
map<int,string>::iterator it;
for(it = mp.begin(); it != mp.end(); it++)//遍历,it为迭代器类型 访问用'->'
for(auto it:mp)//遍历,i为pair类型 访问用'.'