NOIP联赛模板总结

是一个模板总结,待更新。

基本数据结构

字符串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;
			}
		}
	}	
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值