zoukankan      html  css  js  c++  java
  • [复习向] 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....})

  • 相关阅读:
    flex + bison multiple parsers
    Educational Codeforces Round 95 (Rated for Div. 2)
    python学习笔记 day20 序列化模块(二)
    python学习笔记 day20 常用模块(六)
    python 学习笔记 常用模块(五)
    python学习笔记 day19 常用模块(四)
    python学习笔记 day19 常用模块(三)
    python学习笔记 day19 常用模块(二)
    python学习笔记 day19 作业讲解-使用正则表达式实现计算器
    python学习笔记 day19 常用模块
  • 原文地址:https://www.cnblogs.com/pks-t/p/9938275.html
Copyright © 2011-2022 走看看