• [复习向] NOIP板子整理


    • 怎么说呢,整理这个的目的就是为了有个简约的(list),方便以后查阅,复习起来不至于太吃力。
    • 并且……好像重温一遍所有,会更有一些新的认识。这也算是对我所学的一点整理了吧。

    一、并查集的两种方式

    其实就是一个随机化路径压缩,一个启发式合并。

    • 随机化路径压缩:这个地方就是由于f1 = Fa[f2]这句,如是写的人太多了,导致我造数据的时候稍微使一下坏,就可以让原来的好像十分和蔼可亲的(Theta(alpha n) ≈Theta(n))的并查集被卡成狗——毕竟每次合并,深度都起码会增加(1),我可以随随便便让其成为一条链。但如果我是随机合并的,就不存在被卡这种说法了233
    • 按秩合并(启发式合并( m{Heuristic~Merge})): 这其实就是一个贪心,每次把深度小的合并到深度小的上,保证了最坏时间复杂度在(O(nlog 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
    ", 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
    ", 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(nlog 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
    ", !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
    ", !vis[A] ? "Yes" : "No") ;
    	}
    }
    int main(){
    	cin >> N >> M ;
    	if (N <= 1000000) Es::solve1() ; else Euler::solve2() ; return 0 ; 
    }
    
    

    三、最短路的两种方式

    (SPFA + SLF)+乱搞

    其实此处的(SLF)乱搞是借鉴的知乎上的一种方式,即在朴素的(SLF)下,再添加一个交换队头队尾的操作,具体来说:

    • ( m{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], " 
    "[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....})

  • 相关阅读:
    Spring核心思想:IOC(控制反转)、DI(依赖注入)和AOP(面向切面编程)
    synchronized 与 lock锁的异同
    SpringMVC工作流程
    close()和flush()的区别
    MySQL—索引(Index)
    MySQL—事务(ACID)
    MySQL—存储引擎
    周学习笔记(16)——大三下
    周学习笔记(15)——大三下
    周学习笔记(14)——大三下
  • 原文地址:https://www.cnblogs.com/pks-t/p/9938275.html
Copyright © 2020-2023  润新知