【索引】写得好的博客或者部分算法模板

常用

大括号的markdown

\[\left\{ \begin{aligned} ...\\ ...\\ \end{aligned} \right. \]

$$\left\{
\begin{aligned}
...\\
...\\
\end{aligned}
\right.
$$

手动O(2)优化

#pragma GCC optimize(2)

对拍程序

先🐎一份数据生成程序
以a+b为例

#include <bits/stdc++.h>
using namespace std;
int main() {
	srand( time( 0 ) );
	freopen( "data.in", "w", stdout );//将生成数据存入data.in中 
	int a = rand() % 10000, b = rand() % 10000;
	printf( "%d %d", a, b ); 
	return 0;
}

然后是自己的正解 代码

#include <cstdio>
int main() {
	freopen( "data.in", "r", stdin );//从data.in中读入数据
	freopen( "ans.out", "w", stdout );//将程序运行结果保存在ans.out中
	int a, b;
	scanf( "%d %d", &a, &b );
	printf( "%d", a + b ); 
	return 0;
}

接着就是暴力代码 一定要保证暴力是正确的

#include <cstdio>
int main() {
	freopen( "data.in", "r", stdin );//从data.in中读入数据
	freopen( "baoli.out", "w", stdout );//将程序运行结果保存在baoli.out中
	int a, b;
	scanf( "%d %d", &a, &b );
	while( b -- ) a ++;
	printf( "%d", a );
	return 0;
}

准备对拍神器

//新建一个txt文件,先把下面的内容敲进去,然后把文件扩展名(.txt)改成(.bat)
:loop
	data.exe  			//先运行data生成数据
	ans.exe 			//自己的程序运行
	baoli.exe 			//暴力运行
	fc ans.out baoli.out		//两个程序的结果比较
	if errorlevel 1 pause		//如果不一样就会暂停
goto loop 			//一样就继续对拍

最后就可以愉快的对拍了
如果拍出问题就会👇,然后就可以手玩数据
数据在手天下我有
在这里插入图片描述
在这里插入图片描述
如果没有问题,就会一直循环拍下去,👇
所以在考场中,如果你有时间写对拍,就可以写了过后让它自己拍着,先往下做
说不定什么时候回头看一眼,你就拍出问题来了
dalao肯定都是一遍敲过的~~
在这里插入图片描述

随机化

#include <ctime>
#include <algorithm>
using namespace std;
int main() {
	srand( time( 0 ) );
	int n = rand();
}

有些毒瘤题的正解会有将这个数组随机化打乱,避免出题人故意构造卡人,然后大家都能\(AC\)
如果\(WA\)了,不是代码问题,建议自行购买彩票

#include <algorithm>
using namespace std;
int main() {
	random_shuffle( a + 1, a + n + 1 );
	//由计算机来执行将a数组从1~n的数据随机打乱
	return 0;
}

交互

printf();
fflush( stdout );
scanf();

代码

O(n)求树的重心

树的重心:最大儿子的节点数最小(每一个儿子的节点数不超过总节点数的一半)

int root, maxx = 0x3f3f3f3f;
void dfs( int u, int fa ) {
	siz[u] = 1;
	int MaxSon = 0;
	for( int i = 0;i < G[u].size();i ++ ) {
		int v = G[u][i];
		if( v == fa ) continue;
		dfs( v, u );
		siz[u] += siz[v];
		MaxSon = max( MaxSon, siz[v] );
	}
	MaxSon = max( MaxSon, n - siz[u] );
	if( MaxSon < maxx ) {
		maxx = MaxSon;
		root = u;
	}
}

二分图

给定一个二分图\(G\),在\(G\)的一个子图\(M\)中, \(M\)的边集\(\{E\}\)中的任意两条边都不交汇于同一个结点,则称\(M\)是一个匹配

选择边数最大的子图称为最大匹配问题
如果一个匹配中,图的每个顶点都和图中某条边相关联,则称此匹配为完全(完美/完备)匹配

最小边覆盖=最大独立集=总节点数-最大匹配数

交叉染色法判断二分图

bool flag = 1;
memset( vis, -1, sizeof( vis ) );

void dfs( int u, int color ) {
	vis[u] = color;
	for( int i = 0;i < G[u].size();i ++ ) {
		int v = G[u][i];
		if( vis[v] == -1 ) dfs( v, color ^ 1 );
		else if( vis[u] == vis[v] ) {
			flag = 0;
			return;
		}
	}
}

匈牙利算法求二分图最大匹配

十分接地气的易懂博客,nb👍

时间复杂度:邻接矩阵最坏\(O(n^3)\),邻接表\(O(nm)\)
空间复杂度:邻接矩阵\(O(n*m)\),邻接表\(O(n+m)\)
邻接表无论是时间还是空间上都不会劣于邻接矩阵

都0202年了不会还有人在用邻接矩阵吧ε=ε=ε=┏(゜ロ゜;)┛

//洛谷上面模板题:P3386
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
#define maxn 505
vector < int > G[maxn];
int n, m, e, ans;
bool used[maxn];
int belong[maxn];

bool find( int u ) {
	for( int i = 0;i < G[u].size();i ++ ) {
		int v = G[u][i];
		if( used[v] ) continue;
		else {
			used[v] = 1;
			if( ! belong[v] || find( belong[v] ) ) {
				belong[v] = u;
				return 1;
			}
		}
	}
	return 0;
}

int main() {
	scanf( "%d %d %d", &n, &m, &e );
	for( int i = 1, u, v;i <= e;i ++ ) {
		scanf( "%d %d", &u, &v );
		G[u].push_back( v );
	}
	for( int i = 1;i <= n;i ++ ) {
		memset( used, 0, sizeof( used ) );
		if( find( i ) ) ans ++;
	}
	printf( "%d\n", ans );
	return 0;
}

KM算法求二分图最大权完美匹配

模拟KM算法的良心博客,b( ̄▽ ̄)d
hdu卡的不是1,是我
在这里插入图片描述
在这里插入图片描述

//题目:hdu 2255
//但稍微改改是过不了洛谷上的板题的
//这个好像实际上是O(n^4)
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
using namespace std;
#define maxn 305
#define inf 0x3f3f3f3f
int n;
int love[maxn][maxn];	
int ex_girl[maxn];		
int ex_boy[maxn];		
bool vis_girl[maxn];	
bool vis_boy[maxn];	
int match[maxn];		
int need[maxn];			

bool find( int girl ) {
	vis_girl[girl] = 1;
	for( int boy = 1;boy <= n;boy ++ ) {
		if( vis_boy[boy] ) continue;
		int gap = ex_girl[girl] + ex_boy[boy] - love[girl][boy];
		if( ! gap ) {
			vis_boy[boy] = 1;
			if( ! match[boy] || find( match[boy] ) ) {
				match[boy] = girl;
				return 1;
			}
		}
		else need[boy] = min( need[boy], gap ); 
	}
	return 0;
}

int KM() {
	memset( match, 0, sizeof( match ) );
	memset( ex_boy, 0, sizeof( ex_boy ) );
	for( int i = 1;i <= n;i ++ ) {
		ex_girl[i] = love[i][1];
		for( int j = 2;j <= n;j ++ )
			ex_girl[i] = max( ex_girl[i], love[i][j] );
	}
	for( int i = 1;i <= n;i ++ ) {
		memset( need, 0x3f, sizeof( need ) );
		while( 1 ) {
			memset( vis_girl, 0, sizeof( vis_girl ) );
			memset( vis_boy, 0, sizeof( vis_boy ) );
			if( find( i ) ) break;
			int d = inf;
			for( int j = 1;j <= n;j ++ )
				if( ! vis_boy[j] ) d = min( d, need[j] );
			for( int j = 1;j <= n;j ++ ) {
				if( vis_girl[j] ) ex_girl[j] -= d;
				if( vis_boy[j] ) ex_boy[j] += d;
				else need[j] -= d;
			}
		} 
	} 
	int ans = 0;
	for( int i = 1;i <= n;i ++ )
		ans += love[match[i]][i]; 
	return ans;
}

int main() {
	while( ~ scanf( "%d", &n ) ) {
		for( int i = 1;i <= n;i ++ )
			for( int j = 1;j <= n;j ++ )
				scanf( "%d", &love[i][j] );
		printf( "%d\n", KM() );
	}
	return 0;
} 
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
#define int long long
#define INF 1e16
#define maxn 505
vector < pair < int, int > > G[maxn];
int n, m;
int lx[maxn], ly[maxn], slack[maxn], match[maxn];
bool vis[maxn];

void explore( int x ) {
	for( int i = 0;i < G[x].size();i ++ ) {
		int y = G[x][i].first;
		slack[y] = min( slack[y], lx[x] + ly[y] - G[x][i].second );
	}
}

bool find( int x ) {
	for( int i = 0;i < G[x].size();i ++ ) {
		int y = G[x][i].first;
		if( lx[x] + ly[y] == G[x][i].second && ! vis[y] ) {
			vis[y] = 1;
			if( ! match[y] || find( match[y] ) ) {
				match[y] = x;
				return 1;
			}
		}
	}
	return 0;
}

signed main() {
	scanf( "%lld %lld", &n, &m );
	for( int i = 1, u, v, w;i <= m;i ++ ) {
		scanf( "%lld %lld %lld", &u, &v, &w );
		G[u].push_back( make_pair( v, w ) );
	}
	for( int i = 1;i <= n;i ++ ) {
		lx[i] = -INF, ly[i] = 0;
		for( int j = 0;j < G[i].size();j ++ )
			lx[i] = max( lx[i], G[i][j].second );
	}
	for( int i = 1;i <= n;i ++ ) {
		for( int j = 1;j <= n;j ++ )
			vis[j] = 0, slack[j] = INF;
		explore( i );
		while( 1 ) {
			int d = INF, pos;
			for( int j = 1;j <= n;j ++ )
				if( ! vis[j] && slack[j] < d )
					d = slack[j], pos = j;
			if( ! d ) {
				vis[pos] = 1;
				if( ! match[pos] ) {
					/*
					如果不清空
					匈牙利里面的判断!vis[j]就变成vis[j]
					因为我之前肯定是跑过这个点的 
					这样比较暴力
					时间复杂度O(nm+n^3) 
					*/
					memset( vis, 0, sizeof( vis ) );
					find( i );
					//match[pos]=i;
					/*
					这种写法是错误的
					因为pos和i不一定能直接配对
					所以需要像匈牙利一条一条改变配对 
					*/ 
					break;
				}
				else explore( match[pos] );
			}
			else {
				for( int j = 1;j <= n;j ++ )
					if( vis[j] ) {
						ly[j] += d;
						lx[match[j]] -= d;
					}
					else slack[j] -= d;
				lx[i] -= d;
			}
		}
	}
	int ans = 0;
	for( int i = 1;i <= n;i ++ )
		ans += lx[i] + ly[i];
	printf( "%lld\n", ans );
	for( int i = 1;i <= n;i ++ )
		printf( "%lld ", match[i] );
	return 0;
}

二维树状数组

int lowbit( int x ) {
	return x & ( -x );
}

void add( int x, int y ) {
	for( int i = x;i <= n;i += lowbit( i ) )
		for( int j = y;j <= n;j += lowbit( j ) )
			tree[i][j] ++;
}

int query( int x, int y ) {
	int ans = 0;
	for( int i = x;i;i -= lowbit( i ) )
		for( int j = y;j;j -= lowbit( j ) )
			ans += tree[i][j];
	return ( ans & 1 );
}

scanf( "%d %d %d %d", &x1, &y1, &x2, &y2 );
add( x1, y1 );
add( x2 + 1, y1 );
add( x1, y2 + 1 );
add( x2 + 1, y2 + 1 );

点分治

你谷日报

//poj1741
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
#define maxn 10005
#define inf 1e9
vector < pair < int, int > > G[maxn];
int n, k, cnt, maxx, root, S, ans;
bool vis[maxn];
int siz[maxn], dis[maxn];

void dfs( int u, int fa ) {
	siz[u] = 1;
	int MaxSon = 0;
	for( int i = 0;i < G[u].size();i ++ ) {
		int v = G[u][i].first;
		if( v == fa || vis[v] ) continue;
		dfs( v, u );
		siz[u] += siz[v];
		MaxSon = max( MaxSon, siz[u] );		
	}
	MaxSon = max( MaxSon, S - siz[u] );
	if( MaxSon < maxx )
		maxx = MaxSon, root = u;
}

void getdis( int u, int d, int fa ) {
	dis[++ cnt] = d;
	for( int i = 0;i < G[u].size();i ++ ) {
		int v = G[u][i].first, w = G[u][i].second;
		if( vis[v] || v == fa ) continue;
		else getdis( v, d + w, u );
	}
}

int calc( int u, int w ) {
	cnt = 0;
	getdis( u, w, 0 );
	sort( dis + 1, dis + cnt + 1 );
	int l = 1, r = cnt, tot = 0;
	while( l <= r )
		dis[l] + dis[r] <= k ? tot += r - l, l ++ : r --;
	//如果条件成立 说明l和(l,r]的每一个点的距离都≤k 
	return tot;
}

void solve( int u ) {
	vis[u] = 1;
	ans += calc( u, 0 );
	for( int i = 0;i < G[u].size();i ++ ) {
		int v = G[u][i].first, w = G[u][i].second;
		if( vis[v] ) continue;
		ans -= calc( v, w );
		maxx = inf, S = siz[v]; //往下分治 以儿子v为一棵新树的根 所有信息全部更新 
		dfs( v, u );
		solve( root ); //新树的重心分治 
	}
}

int main() {
	while( scanf( "%d %d", &n, &k ) ) {
		if( ! n && ! k ) return 0;
		for( int i = 1;i <= n;i ++ )
			G[i].clear(), vis[i] = 0;
		for( int i = 1, u, v, w;i < n;i ++ ) {
			scanf( "%d %d %d", &u, &v, &w );
			G[u].push_back( make_pair( v, w ) );
			G[v].push_back( make_pair( u, w ) );
		}
		maxx = inf, S = n;
		dfs( 1, 0 );
		ans = 0;
		solve( root );
		printf( "%d\n", ans );
	}
	return 0;
}

优质恰饭

wiki上有很多知识点可以学习!

这个知乎博主真的写得好!

行列式的本质是什么?

如何理解矩阵的「秩」?

矩阵和向量组和线性方程组之间的关系是什么?

如何通俗地解释泰勒公式?

牛顿插值的几何解释是怎么样的?

如何直观地理解拉格朗日插值法?

拉格朗日插值的另外两篇:
带证明的
额...好看的
范德蒙行列式——查找百度百科

又是一个NB知乎博主

怎样更好地理解并记忆泰勒展开式?

Hall定理

hall定理就是判定二分图是否存在完美匹配

充分必要性的证明

一个推论:假设两边的点集分别为\(X,Y\)
则二分图的最大匹配数为\(|X|−max{|W|−|N(W)|}\)
其中\(W\)\(X\)的子集,\(N(W)\)\(W\)的所有相邻点
对于一些特殊的题目,利用该推论,可以免去建图而直接求最大匹配

生成函数

对于序列\(a_i\),生成函数为\(G=\sum_{i=0}^∞a_ix^i\)
利用生成函数的性质解决一些组合问题
可供练习的题目应用

单位根反演

\(O(k)\)的时间内求一个数列(或是生成函数)所有下标是\(k\)的倍数的点值和
有些时候只知道\(k|n\)的点值和还不够,比如求下标\(mod\ k=r\)的点值和
考虑通过函数的平移来解决问题
将该序列的生成函数乘上\(x^{-r}\)
再套用上面的方法就可以得到答案了
你谷日报的单位根反演

浅谈“不动点”求数列通项的方法

b站微积分中文配音讲解

分治FFT 柿子推导过程很清晰

分块详解(▭-▭)✧

数学推导

catlan数的普通生成函数

问:求卡特兰数\(c_0=1,c_n=\sum_{i=0}^{n-1}c_ic_{n-i-1}\)的普通生成函数

\(c_n\)的生成函数为\(C(x)\)

\[C(x)=\sum_{n=0}^∞c_nx^n[=]_{?}\sum_{n=0}^∞\sum_{i=0}^{n-1}c_ic_{n-i-1}x^n \]

\(x^n\)拆分成\(x^ix^{n-i-1}x\),再令\(j=n-i-1\),并进行顺序调整

\[C(x)=\sum_{n=0}^∞\sum_{i=0}^{n-1}c_ic_{n-i-1}x^n[=]_{?}\sum_{i=0}^∞c_ix^i\sum_{j=0}^∞c_jx^jx=C(x)C(x)x \]

诶??\(C(x)=C^2(x)x\),当\(C(x)=0\)也成立,是不是哪里出了点问题
的确!其实初始转换时应该有下标的差异,但是最后变成\(i,j\)后是看不出来的
所以需要修正一下

\[C(x)=\sum_{n=0}^∞c_nx^n≠\sum_{n=1}^∞\sum_{i=0}^{n-1}c_ic_{n-i-1}x^n \]

发现不等号的右边比设置的\(C(x)\)就差了\(n=0\)这一项,即\(c_0x^0=1\),所以加上

真正的推导应该是

\[C(x)=\sum_{n=0}^∞c_nx^n=1+\sum_{n=1}^∞\sum_{i=0}^{n-1}c_ic_{n-i-1}x^n \]

\[\sum_{n=1}^∞\sum_{i=0}^{n-1}c_ic_{n-i-1}x^n=\sum_{i=0}^∞c_ix^i\sum_{j=0}^∞c_jx^jx=C(x)C(x)x \]

\[C(x)-1=C^2(x)x \]

\[C(x)=C^2(x)x+1 \]

解得\(C(x)=\frac{1±\sqrt{1-4x}}{2x}\)

posted @ 2021-02-17 20:45  读来过倒字名把才鱼咸  阅读(62)  评论(0编辑  收藏  举报