$\rm{NOIp}$板子整理
- 怎么说呢,整理这个的目的就是为了有个简约的\(list\),方便以后查阅,复习起来不至于太吃力。
- 并且……好像重温一遍所有,会更有一些新的认识。这也算是对我所学的一点整理了吧。
一、并查集的两种方式
其实就是一个随机化路径压缩,一个启发式合并。
- 随机化路径压缩:这个地方就是由于f1 = Fa[f2]这句,如是写的人太多了,导致我造数据的时候稍微使一下坏,就可以让原来的好像十分和蔼可亲的\(\Theta(\alpha n) ≈\Theta(n)\)的并查集被卡成狗——毕竟每次合并,深度都起码会增加\(1\),我可以随随便便让其成为一条链。但如果我是随机合并的,就不存在被卡这种说法了233
- 按秩合并(启发式合并\(\rm{Heuristic~Merge}\)): 这其实就是一个贪心,每次把深度小的合并到深度小的上,保证了最坏时间复杂度在\(O(n\log n)\)。关于这个复杂度,有一个比较有意思的证明。就是由于对于一个点,每次合并之后,其所在集合内的点数至少*2——不难发现这个结论是平凡的,因为我们每次是把深度较小的集合合并到深度较大的集合。那么也就是对于每个点,最多被拿去合并\(\log n\)次。所以总复杂度上界为\(O(n \log n)\)。
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#define MAXN 200010
using namespace std ;
int N, M, A, B, C, F[MAXN] ;
namespace _Heuristic{
	int H[MAXN] ;
	int find(int x){
		if (x == F[x]) return x ;
		return F[x] = find(F[x]) ;
	}
	inline void Merge(int x, int y){ // Heuristic Merge
		int f1 = find(x), f2 = find(y) ; // Insert the less-height tree into the higher tree
		if (H[f1] > H[f2]) F[f2] = f1 ; //because : H[x] < H[y] -> After Insert H[x] to H[y], H[y] ++ or H[y] == ;
		else if (H[f1] < H[f2]) F[f1] = f2 ; //Therefore, we make the tree the lowest height under meaning .
		else F[f1] = f2, ++ H[f2] ;
	}
	void solve2(){
		fill(H, H + N + 2, 1) ;
		while (M --){
			scanf("%d%d%d", &A, &B, &C) ;
			if (A == 2){
				int f1 = find(B), f2 = find(C) ;
				printf("%c\n", f1 == f2 ? 'Y' : 'N') ;
			}
			else Merge(B, C) ;
		}
	}
}
namespace _Compress{
	int t ;
	int find(int x){
		if (x == F[x]) return x ;
		return F[x] = find(F[x]) ;
	}
	void solve1(){
		srand(time(NULL)) ;
		while (M --){
			scanf("%d%d%d", &A, &B, &C) ;
			if (A == 2){
				int f1 = find(B), f2 = find(C) ;
				printf("%c\n", f1 == f2 ? 'Y' : 'N') ;
			}
			else {
				int f1 = find(B), f2 = find(C) ;
				if (!(t = rand() % 2)) F[f1] = f2 ; else F[f2] = f1 ;//随机化合并
			}
		}
	}
}
int main(){
	cin >> N >> M ;
	for (int i = 1 ; i <= N ; ++ i) F[i] = i  ;
	if (M <= 50000) _Compress::solve1() ; else _Heuristic::solve2() ; return 0 ;
}
二、筛素数的两种方式
其实就是埃氏筛和线性筛啦~
关于埃氏筛复杂度的证明,大概就是每个数会被他所有的质因子都筛一遍,而质因子个数似乎是\(\ln \ln n\)个的,所以复杂度为\(O(n\log \log n)\)的(渐进意义下好像不区分对数底数)。
#include <bitset>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std ;
int N, M ; 
namespace Es{ // Eratosthenes
	#define MAXN 2000100
	bool vis[MAXN] ; int A, i, j ;
	void Ego(){
		vis[1] = vis[0] = 1 ;
 		for (i = 2 ; i <= N ; ++ i){
			if (vis[i])  continue ;
			for (j = i + i ; j <= N ; j += i) vis[j] = 1 ;
		}
	}
	void solve1(){
		Ego() ;
		while (M --)
			scanf("%d", &A), printf("%s\n", !vis[A] ? "Yes" : "No") ;
	}
	#undef MAXN
}
namespace Euler{
	#define MAXN 10001000
	bitset <MAXN> vis ;
	int Prime[MAXN], A, i, j, cnt ;
	void Ego(){
		vis[1] = vis[0] = 1 ;
		for (i = 2 ; i <= N ; ++ i){
			if (!vis[i]) Prime[++ cnt] = i ;
			for (j = 1 ; j <= cnt ; ++ j){
				if (i * Prime[j] > N) break ;
				vis[i * Prime[j]] = 1 ;
				if (!(i % Prime[j])) break ;
			}
		}
	}
	void solve2(){
		Ego() ;
		while (M --)
			scanf("%d", &A), printf("%s\n", !vis[A] ? "Yes" : "No") ;
	}
}
int main(){
	cin >> N >> M ;
	if (N <= 1000000) Es::solve1() ; else Euler::solve2() ; return 0 ;
}
三、最短路的两种方式
\(SPFA + SLF\)+乱搞
其实此处的\(SLF\)乱搞是借鉴的知乎上的一种方式,即在朴素的\(SLF\)下,再添加一个交换队头队尾的操作,具体来说:
- \(\rm{SLF}\)优化:采用双端队列,每次拿自己的\(dist\)与队首元素的\(dist\)进行比较,如果自己比较近(\(dist\)较小),就放到队首;否则放到队尾。
- 交换队首和队尾:每次\(SLF\)之前先按照\(SLF\)的方法把首尾操作一下。
但其实呢,无论如何\(SPFA\)的原理就是一个队列而已,我们做的一切无非就是让他看起来更像一个优先队列而不是\(FIFO\)的队列。所以……该被卡还是会被卡。
#include <deque>
#include <cstdio>
#include <iostream>
#define R register
#define MAXN 200010
#define to(i) E[i].to
#define Inf 2147483647
using namespace std ;
deque <int> q ;
struct Edge{
	int to, next, v ;
}E[MAXN] ; int head[MAXN], cnt ;
int N, M, S, dist[MAXN] ; bool vis[MAXN] ;
inline int qr(){
	int res = 0 ; char c = getchar() ;
	while (!isdigit(c)) c = getchar() ;
	while (isdigit(c)) res = (res << 1) + (res << 3) + c - 48, c = getchar() ;
	return res ;
}
inline void Add(int u, int v, int w) {
	E[++ cnt].to = v, E[cnt].v = w ;
	E[cnt].next = head[u], head[u] = cnt ;
}
inline void SPFA(){
	for (R int i = 1 ; i <= N ; ++ i) dist[i] = Inf ;
	dist[S] = 0, q.push_back(S), vis[S] = 1 ;
	while(!q.empty()){
		R int now = q.front() ;
		q.pop_front(), vis[now] = 0 ;
		for (R int i = head[now] ; i ; i = E[i].next){
			if (dist[to(i)] > dist[now] + E[i].v){
				dist[to(i)] = dist[now] + E[i].v ;
				if (!vis[to(i)]){
					vis[to(i)] = 1 ;
					R int F = q.front(), B = q.back() ;
					if (dist[F] < dist[B]){
						q.pop_front(), q.pop_back() ;
						q.push_front(B), q.push_back(F) ;
						if (dist[B] > dist[to(i)])
							q.push_front(to(i)) ;
						else q.push_back(to(i)) ;
					}
					else if (dist[F] > dist[to(i)])
							q.push_front(to(i)) ;
						else q.push_back(to(i)) ;
				}
			}
		}
	}
}
int main(){
	cin >> N >> M >> S ; int A, B, C ;
	for (R int i = 1 ; i <= M ; ++ i) A = qr(), B = qr(), C = qr(), Add(A, B, C) ;
	SPFA() ; for (R int i = 1 ; i <= N ; ++ i) printf("%d ", dist[i]) ; return 0 ;
}
\(Heap + dijkstra\)
#include <deque>
#include <cstdio>
#include <iostream>
#define R register
#define MAXN 200010
#define to(i) E[i].to
#define Inf 2147483647
using namespace std ;
deque <int> q ;
struct Edge{
	int to, next, v ;
}E[MAXN] ; int head[MAXN], cnt ;
int N, M, S, dist[MAXN] ; bool vis[MAXN] ;
inline int qr(){
	int res = 0 ; char c = getchar() ;
	while (!isdigit(c)) c = getchar() ;
	while (isdigit(c)) res = (res << 1) + (res << 3) + c - 48, c = getchar() ;
	return res ;
}
inline void Add(int u, int v, int w) {
	E[++ cnt].to = v, E[cnt].v = w ;
	E[cnt].next = head[u], head[u] = cnt ;
}
inline void SPFA(){
	for (R int i = 1 ; i <= N ; ++ i) dist[i] = Inf ;
	dist[S] = 0, q.push_back(S), vis[S] = 1 ;
	while(!q.empty()){
		R int now = q.front() ;
		q.pop_front(), vis[now] = 0 ;
		for (R int i = head[now] ; i ; i = E[i].next){
			if (dist[to(i)] > dist[now] + E[i].v){
				dist[to(i)] = dist[now] + E[i].v ;
				if (!vis[to(i)]){
					vis[to(i)] = 1 ;
					R int F = q.front(), B = q.back() ;
					if (dist[F] < dist[B]){
						q.pop_front(), q.pop_back() ;
						q.push_front(B), q.push_back(F) ;
						if (dist[B] > dist[to(i)])
							q.push_front(to(i)) ;
						else q.push_back(to(i)) ;
					}
					else if (dist[F] > dist[to(i)])
							q.push_front(to(i)) ;
						else q.push_back(to(i)) ;
				}
			}
		}
	}
}
int main(){
	cin >> N >> M >> S ; int A, B, C ;
	for (R int i = 1 ; i <= M ; ++ i) A = qr(), B = qr(), C = qr(), Add(A, B, C) ;
	SPFA() ; for (R int i = 1 ; i <= N ; ++ i) printf("%d ", dist[i]) ; return 0 ;
}
四、矩阵快速幂
主要是成员函数的写法,是从\(rqy\)的代码里抄来的。
#include <cstdio>
#include <cstring>
#include <iostream>
#define LL long long
#define Mod 1000000007
using namespace std ;
LL N, K ;
struct Matrix{
	LL M[200][200] ;
	void clear() { memset(M, 0, sizeof(M)) ;}
	void reset() {
		clear() ;
		for (int i = 1 ; i <= N ; ++ i) M[i][i] = 1 ;
	}
	Matrix friend operator *(const Matrix&A, const Matrix &B){
		Matrix Ans ; Ans.clear() ;
		for (int i = 1 ; i <= N; ++ i)
			for (int j = 1 ; j <= N ; ++ j)
				for (int k = 1 ; k <= N; ++ k)
					Ans.M[i][j] = (Ans.M[i][j] + A.M[i][k] * B.M[k][j]) % Mod ;
		return Ans ;
	}
	Matrix friend operator +(const Matrix&A, const Matrix &B){
		Matrix Ans ; Ans.clear() ;
		for (int i = 1 ; i <= N; ++ i)
			for (int j = 1 ; j <= N ; ++ j)
					Ans.M[i][j] = (A.M[i][j] + B.M[i][j]) % Mod ;
		return Ans ;
	}
} qwq, unit ;
inline Matrix expow(Matrix T, LL P){
	Matrix Ans ; Ans.reset() ;
	while (P){
		if (P & 1) Ans = Ans * T ;
		T = T * T, P >>= 1 ;
	}
	return Ans ;
}
int main(){
	cin >> N >> K ;
	for (int i = 1 ; i <= N ; ++ i)
		for (int j = 1 ; j <= N ; ++ j)
			cin >> qwq.M[i][j] ;
	qwq = expow(qwq, K) ;
	for (int i = 1 ; i <= N ; ++ i)
		for (int j = 1 ; j <= N ; ++ j)
			printf("%lld%c", qwq.M[i][j], " \n"[j == N]) ;
}
五、二分图匹配
虽然好像板子比较好写的样子……不过我还是觉得没准\(Dinic\)更好一些\(233\).
#include <cstdio>
#include <cstring>
#include <iostream>
#define R register
#define MAXN 2000100
#define to(k) E[k].to
using namespace std  ;
struct Edge{
	int to, next, v ;
}E[MAXN] ; int head[MAXN], Ans, cnt ;
int N, M, Ew, A, B, used[MAXN] ; bool vis[MAXN] ;
inline void Add(int u, int v) {
	if (u < 1 || v < 1 || u > N || v > M) return ;
	E[++ cnt].to = v, E[cnt].next = head[u], head[u] = cnt ;
}
bool path(int u){
	for (int k = head[u] ; k ; k = E[k].next){
		if (!vis[to(k)]){
			vis [to(k)] = 1 ;
			if (!used[to(k)] || path(used[to(k)])){
				used[to(k)] = u ;
				return 1 ;
			}
		}
	}
	return 0 ;
}
int main(){
	cin >> N >> M >> Ew ;
	while(Ew --) scanf("%d%d", &A, &B), Add(A, B) ;
	for (R int i = 1 ; i <= N ; ++ i)
		memset(vis, 0, sizeof(vis)), Ans += (int)path(i) ;
	cout << Ans << endl ; return 0 ;
}
\(\mathscr{To~Be~Continued....}\)
随机推荐
- linux7 安装SVN
			1.安装Linux虚拟机-- 安装后配置a.停止防火墙# systemctl stop firewalld.service# systemctl disable firewalld.service# ... 
- 【 js 基础 】【读书笔记】作用域和闭包
			一.编译过程 常见编译性语言,在程序代码执行之前会经历三个步骤,称为编译. 步骤一:分词或者词法分析 将由字符组成的字符串分解成有意义的代码块,这些代码块被称为词法单元. 例子: var a = 2 ... 
- PHP中按值传递和引用传递的区别
			有次跟朋友讨论对象传值的方式时提到引用传值时,在大脑中搜索五秒钟,果断确定在这两个项目当中并没有用到.今天去问了一下度娘,顺便做了个小测试: 按值传递: 引用传递: 按值传递中原来参数的值在调用其他函 ... 
- H5添加禁止缩放功能
			<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scal ... 
- js-jQuery性能优化(一)
			来自于<锋利的jQuery> 1.使用最新版本的jQuery类库 jQuery每一个新的版本都会较上一版本进行BUG修复和一些优化,同时也会包含一些创新,所以建议使用最新版本的jQuery ... 
- 从零开始学习html(十五)css样式设置小技巧——上
			一.水平居中设置-行内元素 <!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> ... 
- Maven学习(三)maven原理概念详述
			maven相关概念 maven坐标 Maven世界拥有大量构建,当我们需要引用依赖包是,需要用一个用来唯一标识去确定唯一的一个构建.如果拥有了统一规范,就可以把查找工作交给机器. 类似于空间找点的坐标 ... 
- 《Javascript权威指南-第6版》
			第3章 类型.值和变量 3.2 文本 3.2.1 字符串直接量 建议:在javascript中使用单引号表示字符串,在HTML中使用双引号表示字符串; 3.2.2 转义字符 \n 换行符 \r 回车符 ... 
- 腾讯云Centos安装nginx
			使用的是腾讯云主机,选择的镜像如下: Centos7+ 64bit; nginx 1.7.12 1.安装依赖 yum -y install gcc gcc-c++ wget net-tools pcr ... 
- WebAPI返回时间数据不带T
			最近一段时间项目里面使用WebAPI比较多,但是在返回时间数据的时候回默认带上T,就像这样子 "2016-04-21T13:26:17.4701811+08:00", 这样的数据在 ... 
