是一个模板总结,待更新。
基本数据结构
字符串KMP模式匹配
next[i]表示在A中以i结尾的非前缀子串与A的前缀能够匹配的最大长度。
f[i]表示B中以i结尾的子串与A的前缀能够匹配的最长长度。
//求next[]数组
next[1] = 0;
for(int i = 2, j = 0; i <= n; i++)
{
while(j>0 && a[i]!=a[j+1]) j = next[j];
if(a[i] == a[j+1]) j++;
next[i] = j;
}
//求f[]数组
for(int i = 1, j = 0; i <= m; i++)
{
while( j>0 && (j==n||b[i]!=a[j+1]) ) j = nect[j];
if(a[i] == a[j+1]) j++;
next[i] = j;
}
二叉堆
int heap[MAXN], n;
//插入操作
void up(int p)
{
while(p > 1)
{
if(heap[p] > heap[p/2])
{
swap(heap[p], heap[p/2]);
p /= 2;
}
else break;
}
}
void Insert(int Val)
{
heap[++n] = Val;
up(n);
}
//堆顶删除操作
void down(int p)
{
int s = p*2;
while(s <= n)
{
if(s<n && heap[s]<heap[s+1]) s++;
if(heap[s]>heap[p])
{
swap(heap[s], heap[p]);
p = s, s = p*2;
}
else break;
}
}
void Extract()
{
heap[1] = heap[n--];
down(1);
}
//删除操作
void Remove(int k)
{
heap[k] = heap[n--];
up(k);
down(k);
}
数据结构进阶
线段树
struct Node {
int l_Child, r_Child;
int Data;
int max_Data, min_Data;
}t[MAXN * 4];
void Build(int Left, int Right, int p)
{
if(Left == Right)
{
t[p].Data = a[Left];
return ;
}
else int Mid = Left + (Right - Left) / 2;
Build(Left, Mid, p*2);
Build(Mid+1; Right, p*2+1);
}
Build(1, n, 1);
void Down(int p)
{
if(t[p].Add)
{
t[p*2].sum = t[p].add * (t[p*2].right-t[p*2].left+1);
t[p*2+1].sum = t[p].add * (t[p*2+1].right-t[p*2+1].left+1);
t[p*2].add += t[p].add;
t[p*2+1].add += t[p].add;
t[p].add = 0;
}
}
数论
质数
埃式筛法
int noPrime[MAXN], Prime[MAXN], tot;
void Prime(int n)
{
memset(noPrime, sizeof(noPrime));
for(int i = 2; i <= n; i++)
{
if(noPrime[i]) continue;
Prime[++tot] = i;
for(int j = i; j <= n / i; j++) noPrime[i*j] = 1;
}
}
质因数分解
void Divide(int n)
{
tot = 0;
for(int i = 1; i*i <= n; i++)
{
if(!(n%i))
{
p[++tot] = i;c[m] = 0;
while(!(n%i)) n /= i, c[m]++;
}
}
if(n > 1)//***
p[++m] = n, c[m] = 1;
}
最大公约数
int gcd(int x, int y)
{
if(!y) return x;
else return gcd(y, x%y);
}
拓展欧几里得
int x = 1, y = 0;
int Exgcd(int a, int b)
{
if(b==0) return a;
int d = Exgcd(b, a%b);
z = x, x = y;
y = z - y * (a / b);
return d;
}
欧拉函数
//n
int Phi(int n)
{
int Ans = n;
for(int i = 2; i*i <= n; i++)
{
if(!(n%i))
{
Ans = Ans / i * (i-1);
while(!(n%i)) n /= i;
}
}
if(n > 1) Ans = Ans / n * (n-1);
return Ans;
}
欧拉筛太难背了呕呕呕
费马小定理
如果p为质数,则有ap-1 ≡ 1(mod p)。
乘法逆元
b|a, a/b ≡ a*x (mod m), b-1(mod m)
图论
最基础的树和图的遍历
//树的遍历
int Depth[MAXN];
void BFS()
{
queue<int> q;
q.push(1); Depth[1] = 1;
while(q.size())
{
int x = q.front(); q.pop();
for(int i = Head[x]; i; i = Next[i])
{
int y = To[i];
if(Depth[y]) continue;
Depth[y] = Depth[x] + 1;
q.push(y);
}
}
}
图的遍历及求联通块个数
void Cone(int x)
{
for(int i = Head[x]; i; i = Next[i])
{
int y = To[i];
if(!vis[y]) vis[y] = 1, Cone(y);
}
}
int main()
{
memset(vis, 0, sizeof(vis));
for(int i = 1; i <= n; i++)
{
if(!vis[i]) Cnt++, Cone(i);
}
}
倍增求Lca
void BFS()
{
queue<int> q;
q.push(1); Depth[1] = 1;
while(q.size())
{
int x = q.front(); q.pop();
for(int i = Head[x]; i; i = Next[i])
{
int y = To[i];
if(Depth[y]) continue;
Depth[y] = Depth[x] + 1;
f[y][0] = x;
for(int j = 1; j <= t; j++)
f[y][j] = f[f[y][j-1]][j-1];
q.push(y);
}
}
}
int Lca(int x, int y)
{
if(Depth[x] > Depth[y]) swap(x, y);
for(int i = t; i >= 0; i--)
if(Depth[f[y][i]] >= Depth[x]) y = f[y][i];
if(x == y) return x;
for(int i = t; i >= 0; i--)
if(f[x][i] != f[y][i]) y = f[y][i], x = f[x][i];
return f[x][0];
}
并查集
int Dist[MAXN], fa[MAXN]
int Find(int son)
{
if(fa[son] == son) return son;
return fa[son] = get(fa[son]);
}
int Find_(int son)
{
if(fa[son] == son) return son;
int root = Find_(fa[son]);
Dist[son] = Dist[fa[son]];
return fa[son] = root;
}
int main()
{
for(int i = 1; i <= n; i++) fa[i] = i;
}
求最小生成树
//Kruskal
struct Node {
int x, y, Dist;
}Edge[MAXN];
bool comp(const Node &a, const Node &b) { return a.Dist < b.Dist; }
int Find(int son)
{
if(fa[son] == son) return son;
return fa[son] = get(fa[son]);
}
void Kruscal()
{
for(int i = 1; i <= n; i++)
{
int fa1 = Find(Edge[i].x), fa2 = Find(Edge[i].y);
if(fa1 == fa2) continue;
fa[fa1] = fa2;
Ans += Edge[i].z;
}
}
int main()
{
for(int i = 1; i <= n; i++) fa[i] = i;
sort(Edge+1, Edge+m+1, comp);
Kruskal();
}
//Prim 多用于稠密图
int Dist[MAXN], vis[MAXN], Edge[MAXN][MAXN];
void Prim()
{
memset(Dist, 0x3f, sizeof(Dist));
memset(vis, 0, sizeof(vis));
Dist[1] = 0;
for(int i = 1; i , n; i++)
{
int x = 0;
for(int j = 1; j <= n; j++)
if(!vis[i] && (x==0 || Dist[j]<Dist[x])) x = j;
vis[x] = 1;
for(int y = 1; y <= n; y++)
if(!v[y]) Dist[y] = min(Edge[x][y], Dist[y]);
}
}
int main()
{
Prim();
for(int i = 2; i <= n; i++) Ans += Dist[i];
}
图论怎么能忘了怎么求最短路呢
//Floyd n<=1000
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
Dist[i][j] = 0x3f3f3f3f;
Dist[i][i] = 0;
}
for(int k = 1; k <= n; k++)
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
Dist[i][j] = min(Dist[i][j], Dist[i][k]+Dist[k][j]);
//Dijlkstra + 堆优化
priority_queue< pair<int,int> > q;
void Dijkstra()
{
memset(Dist, 0x3f, sizeof(Dist));
memset(vis, 0, sizeof(vis));
Dist[1] = 0;
q.push(make_pair(0,1));
while(q.size())
{
int x = q.top().second; q.pop();
if(vis[x]) continue;
vis[x] = 1;
for(int i = Head[x]; i; i = Next[i])
{
int y = To[i], z = Edge[i];
if(Dist[y] < Dist[x]+z)
{
Dist[y] = Dist[x]+z;
q.push(make_pair(-Dist[y], y));
}
}
}
}
void Spfa()
{
queue<int> q;
memset(Dist, 0x3f3f3f3f, sizeof(Dist));
memset(vis, 0, sizeof(vis));
q.push(1); Dist[1] = 0; vis[1] = 1;
while(q.size())
{
int x = q.front(); q.pop(); vis[x] = 0;
for(int i = Head[x]; i; i = Next[i])
{
int y = To[i], z = Dist[i];
if(Dist[y] > Dist[x]+z)
{
Dist[y] = Dist[x]+z;
if(!vis[y]) q.push(y), vis[y] = 1;
}
}
}
}