NOIPの模板总结

1 篇文章 0 订阅

写在前面:
十分对不住看本篇博客的朋友,因为这篇博客是未完全写完的,之后会更新但是不知道是什么时候了,蒟蒻博主已经灰暗的退役了。但还是希望能做出一点微小的贡献,希望能对大家有帮助。

数论

#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;

const int mmod = 1e9 + 7 , N = 5000 ;
int C[5005][5005] , fac[100005] , inv[100005] , D[100005] ;

int p[1000005] , phi[1000005] , miu[1000005] , tao[1000005] , d[1000005] , topp ;
bool isnotp[1000005] ;
void get_P(){
	phi[1] = 0 ;
	miu[1] = 1 ;
	for( int i = 2 ; i <= 1000000 ; i ++ ){
		if( !isnotp[i] ){
			p[++topp] = i ;
			phi[i] = i - 1 ;
			miu[i] = -1 ;
			tao[i] = 2 , d[i] = 1 ;
		}
		for( int j = 1 ; j <= topp && i * p[j] <= 1000000 ; j ++ ){
			if( i % p[j] == 0 ){
				//i中包含 p[j] ,现在又多了一个 p[j]
				//也就是原来 i 和它互质的数,记为 k ,现在变成了 1*k,2*k,3*k...p[j]*k
				//而这些 1*k,2*k,3*k...p[j]*k 一定和 i*p[j]互质
				//http://blog.csdn.net/Lytning/article/details/24432651
				phi[ i*p[j] ] = phi[i] * p[j] ;
				//miu根据定义可得
				miu[ i*p[j] ] = 0 ;
				//num = p1^t1 + p2^t2 + ... + pn^tn ;
				//tao[num] = ( t1 + 1 ) * ( t2 + 1 ) * ... * ( tn + 1 ) ;
				//tao[ num*p[j] ] = tao[num] / ( d[i] + 1 ) * ( d[i] + 1 + 1 ) ;
				tao[ i*p[j] ] = tao[i] / ( d[i] + 1 ) * ( d[i] + 2 ) ;
				d[ i*p[j] ] = d[i] + 1 ;
				break ;
			}
			phi[ i*p[j] ] = phi[i] * phi[ p[j] ] ;
			miu[ i*p[j] ] = miu[i] * -1 ;
			tao[ i*p[j] ] = tao[i] * 2 ;
			d[ i*p[j] ] = 1 ;
		}
	}
}


//杨辉三角:C[i][j] = C[i-1][j] + C[i-1][j-1] 
void preWork_C() {
	C[0][0] = 1 ;
	for( int i = 1 ; i <= 5000 ; i ++ ) {
		C[i][0] = 1 ;
		for( int j = 1 ; j <= i ; j ++ )
			C[i][j] = ( C[i-1][j] + C[i-1][j-1] ) %mmod ;
	}
}

//阶乘:fac[i] = fac[i-1] * i 
void preWork_fac() {
	fac[0] = 1 ;
	for( int i = 1 ; i <= 100000 ; i ++ )
		fac[i] = 1LL * fac[i-1] * i %mmod ;
}

//错排公式:D[i] = ( i - 1 )*( D[i-1] + D[i-2] ) 
void preWork_cuopai() {
	D[1] = 0 ; D[2] = 1 ;
	for( int i = 3 ; i <= 100000 ; i ++ )
		D[i] = 1LL * ( i - 1 ) * ( D[i-1] + D[i-2] ) %mmod ;
}

//
int gcd( int a , int b ) {
	if( !b ) return a ;
	return gcd( b , a%b ) ;
}

//
long long exgcd( long long a , long long b , long long &x , long long &y ) {
	if( !b ) {
		x = 1 , y = 0 ;
		return a ;
	} else {
		long long xx , yy , d = exgcd( b , a%b , xx , yy ) ;
		x = yy , y = xx - a / b * yy ;
		return d ;
	}
}

//只有x和p互质时,才存在逆元 
int get_inv( int x , int p ) {
	long long inv , tmp ;
	exgcd( x , p , inv , tmp ) ;
	return ( inv %mmod + mmod ) %mmod ;
}

//同上,阶乘的逆元,用于算组合数 
void preWork_facinv() {
	inv[100000] = get_inv( fac[100000] , mmod ) ;
	for( int i = 99999 ; i >= 0 ; i -- )
		inv[i] = 1LL * inv[i+1] * ( i + 1 ) %mmod ;
}

//组合数: n! / m! / (n-m)! = n! * inv[m!] * inv[(n-m)!] 
int comb( int n , int m ){
	return 1LL * fac[n] * inv[m] %mmod * inv[n-m]%mmod ;
}

//卡特兰公式: C(2n,n-1)/n 
int catalan( int x ){
	return 1LL * comb( 2 * x , x - 1 ) * get_inv( x , mmod ) %mmod ;
}

//要求模数为质数 
long long Lucas( long long n , long long m ) {
	if( n < m ) return 0 ;
	if( n >= mmod )
		return Lucas( n/mmod , m/mmod ) * comb( n%mmod , m%mmod ) ;
	else return C[n][m] ;
}

//要求mi两两互质
//http://blog.csdn.net/clove_unique/article/details/54571216
void CRT(){
	int cnt , m[100] , c[100] ;
	long long M = 1 , ans = 0 ;
	scanf( "%d" , &cnt ) ;
	for( int i = 1 ; i <= cnt ; i ++ ){
		scanf( "%d%d" , &m[i] , &c[i] ) ;
		M *= m[i] ;
	}
	for( int i = 1 ; i <= cnt ; i ++ ){
		long long Mi = M / m[i] ;
		ans = ( ans + c[i] * Mi %mmod * get_inv( Mi , m[i] ) ) %mmod ;
	}
}

int main( int argc , char *argv[] ) {
	preWork_C() ;
	preWork_fac() ;
	preWork_facinv() ;
	get_P() ;
	for( int i = 1 ; i <= N ; i ++ ){
		printf( "%d" , comb( 2 * i , i - 1 ) / i ) ;
		getchar() ;
	}
	return 0 ;
}

##GCD

LL gcd(LL a, LL b) { return !b ? a : gcd(b, a%b); }

##EXGCD

// gcd(a, b) = a*x+b*y;
LL exgcd(LL a, LL b, LL &x, LL &y) {
	if(!b) { x = 1; y = 0; return a; }
	LL x0, y0, d = exgcd(b, a%b, x0, y0);
	x = y0; y = x0-(a/b)*y0;
	return d;
}

LUCAS

// C(n,m) =  C(n/p, m/p)*C(n%p, m%p) (mod p) (when 0 <= m <= n)
// C(n,m) = 0 (mod p)	(when m > n)
LL lucas(LL n, LL m, LL MOD) {
	if(m > n) return 0;
	if(n < MOD) return comb(n, m, MOD);
	return lucas(n/MOD, m/MOD, MOD)*comb(n%MOD, m%MOD, MOD)%MOD;
}

扩展LUCAS

逆元

qpow(x, MOD-2);
// a^-1
LL inv(LL a, LL MOD) {
	LL x,y;
	exgcd(a, MOD, x, y);
	return (x%MOD+MOD)%MOD;
} 

	vfac[0] = vfac[1] = 1;
	for(int i = 2; i <= maxn; i++) vfac[i] = (MOD-MOD/i)*vfac[MOD%i]%MOD;

CRT

// x = a (mod m)
LL crt(LL *va, LL *vm, int n) {
	LL sum = 1, ans = 0;
	for(int t = 0; t < n; t++) sum *= vm[t];
	for(int t = 0; t < n; t++) {
		LL mi = sum/vm[t], vmi = inv(mi, vm[t]);
		ans += mi*vmi%sum*va[t]%sum;
		if(ans >= sum) ans -= sum;
	}
	return ans;
}

扩展CRT

排列组合

卡特兰数

inline LL catalan(LL N, LL MOD) { return comb(2*N, N, MOD)/(N+1); }

错排

// D(1) = 0, D(2) = 1
// D(n) = (n-1)*(D(n-1)+D(n+2))
LL D[maxn];
void cuopai(int N, int MOD) {
	D[1] = 0, D[2] = 1;
	for(int i = 3; i <= N; i++) D[i] = (i-1)*(D[i-1]+D[i-2])%MOD;
}

斯特林数

快速幂

inline LL powermod(LL a, LL b, LL MOD) {
    LL ans = 1; a %= MOD;
    while(b) {
        if(b&1) ans = ans*a%MOD, b--;
        b >>= 1; a = a*a%MOD;
    }
    return ans%MOD;
}

矩阵快速幂

筛法

//筛法求素数 
int pri[maxn]; 
void checkprime(int N) {
	pri[1] = 1;
	for(int i = 2; i <= sqrt(N); i++) if(!pri[i])
		for(int j = 2; j*i <= N; j++) pri[i*j] = 1;
} 

线性筛

//线性筛 
bool isprime[maxn];
int prime[maxn],mu[maxn],phi[maxn],tao[maxn],d[maxn],cnt_pri;
void linear_sieve(int N) {
	isprime[1] = mu[1] = phi[1] = tao[1] = 1; d[1] = 0;
	for(int i = 2; i <= N; i++) {
		if(!isprime[i]) prime[++cnt_pri] = i, mu[i] = -1, phi[i] = i-1, tao[i] = 2, d[i] = 1;
		for(int t = 0; t < cnt_pri; t++) {
			int j = prime[t]*i;
			if(j > N) break;
			isprime[j] = 1;
			mu[j] = mu[prime[t]]*mu[i];
			phi[j] = phi[prime[t]]*phi[i];
			tao[j] = tao[i]<<1;
			d[j] = 1;
			if(!(i%prime[t])) { mu[j] = 0; phi[j] = prime[t]*phi[i]; tao[j] = tao[i]/(d[i]+1)*(d[i]+2); d[j] = d[i]+1; break; }
		}
	}
}

高斯消元

线性基

图论

最短路

floyd

for(int i = 1; i <= n; i++)
	for(int j = 1; j <= n; j++)
		for(int k = 1; k <= n; k++)
			mp[i][j] = min(mp[i][j], mp[i][k]+mp[k][j]);

dijkstra

#include <bits/stdc++.h>
#define LL long long 

using namespace std;

const int maxn = 1e5+5;
const int maxm = 2e5+5;
LL dis[maxn],w[maxm<<1];
int nxt[maxm<<1],to[maxm<<1],head[maxn<<1];
int n,m,p,tot;
queue<int> q;
bool vis[maxn];

inline void edge(int x, int y, int z) {
	nxt[++tot] = head[x]; head[x] = tot; w[tot] = z; to[tot] = y;
	nxt[++tot] = head[y]; head[y] = tot; w[tot] = z; to[tot] = x;
}

void dij(int u) {
	q.push(u);
	vis[u] = 1;
	while(!q.empty()) {
		int x = q.front();
		q.pop();
		vis[x] = 0;
		for(int i = head[x]; i; i = nxt[i]) {
			int y = to[i];
			if(dis[x]+w[i] < dis[y]) {
				dis[y] = dis[x]+w[i];
				if(!vis[y]) vis[y] = 1, q.push(y);
			}
		}
	}
}

int main() {
	scanf("%d%d%d",&n,&m,&p);
	for(int a,b,c,i = 1; i <= m; i++) scanf("%d%d%d",&a,&b,&c), edge(a, b, c);	
	for(int i = 2; i <= n; i++) dis[i] = INF;
	dij(1);
	printf(AUTO, dis[n]+dis[p]);
	return 0;
}


SPFA

建议不用

差分约束系统

最短路径树

二分图

匈牙利

二分图染色

find union set

路径压缩

#include <cstdio>

const int maxn = 1e6+5;
int n,fa[maxn],siz[maxn];

int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }

void unionn(int x, int y) {
	int fx = find(x), fy = find(y);
	if(fx == fy) return ;
	fa[fx] = fy;
}//naive

int main () {
	for(int i = 1; i <= n; i++) fa[i] = i;
	return 0;
} 

按秩合并

#include <cstdio>
#include <cstring>
#include <algorithm>

const int N = 500005;

template <class T> inline void read(T &x) {
    int flag = 1; x = 0;
    char ch = (char)getchar();
    while(ch <  '0' || ch >  '9') { if(ch == '-')  flag = -1; ch = (char)getchar(); }
    while(ch >= '0' && ch <= '9') { x = (x<<1)+(x<<3)+ch-'0'; ch = (char)getchar(); }
    x *= flag;
}

int n,m,fa[N],rank[N],tim,w[N],dep[N];

int Merge(int u, int v) {
	if(rank[u] > rank[v]) fa[v] = u, w[v] = tim;
	else {
		fa[u] = v; w[u] = tim;
		if(rank[u] == rank[v]) rank[v]++;
	}
}

int Find(int x) { return fa[x] == x ? x : Find(fa[x]); }

void Dfs(int u) {
	if(fa[u] == u) return;
	Dfs(fa[u]);
	dep[u] = dep[fa[u]] + 1;
}

int Query(int u, int v) {
	int ans = 0;
	Dfs(u), Dfs(v);
	if(dep[u] < dep[v]) std :: swap(u, v);
	while(dep[u] > dep[v] && u != v) ans = std :: max(ans, w[u]), u = fa[u];
	while(u != v) ans = std :: max(std :: max(ans, w[u]), w[v]), u = fa[u], v = fa[v];
	return ans;
}

int main() {
	read(n), read(m);
	for(int i = 1; i <= n; i++) fa[i] = i;
	int lsa = 0, opt, a, b;
	for(int i = 1; i <= m; i++) {
		read(opt), read(a), read(b);
		a ^= lsa, b ^= lsa;
		int tp1 = Find(a), tp2 = Find(b);
		if(!opt) {
			tim++;
			if(tp1 != tp2) Merge(tp1, tp2);
		}
		else 
			if(tp1 != tp2) printf("0\n"), lsa = 0;
			else lsa = Query(a, b), printf("%d\n",lsa);
	}
	return 0;
}

欧拉回路

Tarjan

割点

void tarjan(int u, int fa) {
    dfn[u] = low[u] = ++idc;
    for(int i = head[u]; i; i = e[i].next) {
        int v = e[i].v;
        if(v == fa) continue;
        if(!dfn[v]) {
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
            if(low[v] >= dfn[u]) iscut[u]++;
        } else low[u] = min(low[u], dfn[v]);
    }
}

桥边

void tarjan(int u, int fa) {
    dfn[u] = low[u] = ++idc;
    int times = 0;
    for(int i = head[u]; i; i = e[i].next) {
        int v = e[i].v;
        if(!dfn[v]) {
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
            if(low[v] > dfn[u]) bridge[++bridgecnt] = i;
        } else if(v == fa) {
            if(times) low[u] = min(low[u], dfn[v]);
            times++;
        } else low[u] = min(low[u], dfn[v]);
    }
}

缩点

#include <iostream>
#include <cstdio>

using namespace std;

int n,m,d,cnt,scc,ind,top;
int v[105],w[105],sv[105],sw[105];
int dfn[105],low[105],blg[105];
int q[105],f[105][505],in[505];
struct edge { int to,nxt; } e[505],ed[505];
int lst[105],lst2[105];
bool inq[105];

template <class T> inline void read(T &x) {
    int flag = 1; x = 0;
    char ch = (char)getchar();
    while(ch <  '0' || ch >  '9') { if(ch == '-')  flag = -1; ch = (char)getchar(); }
    while(ch >= '0' && ch <= '9') { x = (x<<1)+(x<<3)+ch-'0'; ch = (char)getchar(); }
    x *= flag;
}

inline void add(int u, int v) { e[++cnt].to = v; e[cnt].nxt = lst[u]; lst[u] = cnt; }

inline void ins(int u, int v) { in[v] = 1; ed[++cnt].to = v; ed[cnt].nxt = lst2[u]; lst2[u] = cnt; }

void tarjan(int x) {
    int now = 0;
    low[x] = dfn[x] = ++ind;
    q[++top] = x; inq[x] = 1;
    for(int i = lst[x]; i; i = e[i].nxt)
        if(!dfn[e[i].to]) tarjan(e[i].to), low[x] = min(low[x], low[e[i].to]); 
        else if(inq[e[i].to]) low[x] = min(low[x], dfn[e[i].to]);
    if(low[x] == dfn[x]) {
        scc++;
        while(now != x) {
			inq[now = q[top--]] = 0;
            blg[now] = scc;
            sv[scc] += v[now];
            sw[scc] += w[now];
        }
    }
}

void dp(int x) {
    for(int i = lst2[x]; i; i = ed[i].nxt) {
        dp(ed[i].to);
        for(int j = m-sw[x]; j >= 0; j--)
            for(int k = 0; k <= j; k++) f[x][j] = max(f[x][j], f[x][k]+f[ed[i].to][j-k]);
    }
    for(int j = m; j >= 0; j--) f[x][j] = j >= sw[x] ? f[x][j-sw[x]]+sv[x] : 0;
}

int main() {
    read(n); read(m);
    for(int i = 1; i <= n; i++) read(w[i]);
    for(int i = 1; i <= n; i++) read(v[i]);
    for(int i = 1; i <= n; i++) { read(d); if(d) add(d, i); }
    for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i);
    cnt = 0;
    for(int x = 1; x <= n; x++)
        for(int i = lst[x]; i; i = e[i].nxt)
            if(blg[e[i].to] != blg[x]) ins(blg[x], blg[e[i].to]);
    for(int i = 1; i <= scc; i++) if(!in[i]) ins(scc+1, i);
    dp(scc+1);
    printf("%d\n",f[scc+1][m]);
    return 0;
}

MST

#include<cstdio>
#include<ctime>
#include<iostream>
#include<algorithm>

using namespace std;

const int maxn = 305;
int n,x,tot,ans;
int fa[maxn];
struct edge {
	int u,v,val;
	bool operator < (const edge &a) const { return val < a.val; }
} e[maxn*maxn];

int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }

inline void unionn(int a, int b) { fa[find(a)] = find(b); }

int main() {
	scanf("%d",&n);
	for(int i = 1; i <= n; i++) scanf("%d",&x), e[++tot].u = 0, e[tot].v = i, e[tot].val = x, fa[i] = i;
	for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++)
		scanf("%d",&x), e[++tot].u = i, e[tot].v = j, e[tot].val = x;
	sort(e+1, e+1+tot);
	for(int i = 1; i <= tot; i++) if(find(e[i].u) != find(e[i].v)) ans += e[i].val, unionn(e[i].u, e[i].v);
	printf("%d",ans);
	return 0;
}

拓扑排序

树链剖分

重心

直径

dfs序

LCA

倍增
常数查询

数据结构

数组

链表

队列

有限队列

ST表

手写堆

STL

左偏树

#include <cstdio>
#include <cstring>
#include <algorithm>
#define clr(x) memset(x, 0, sizeof x)
#define digit (ch <  '0' || ch >  '9')

using namespace std;

template <class T> inline void read(T &x) {
	int flag = 1; x = 0;
	register char ch = getchar();
	while( digit) { if(ch == '-')  flag = -1; ch = getchar(); }
	while(!digit) { x = (x<<1)+(x<<3)+ch-'0'; ch = getchar(); }
	x *= flag;
}

const int N = 100005;
int n, m;
int rs[N],ls[N],fa[N],dis[N],str[N];

int merge(int x, int y) {
	if(!x || !y) return x+y;
	if(str[x] < str[y]) swap(x, y);
	rs[x] = merge(rs[x], y);
	if(dis[rs[x]] > dis[ls[x]]) swap(ls[x], rs[x]);
	dis[x] = dis[rs[x]]+1;
	fa[ls[x]] = fa[rs[x]] = fa[x] = x;
	return x; 
}

int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }

int main() {
	while(~scanf("%d",&n)) {
		clr(ls), clr(rs), clr(dis);
		dis[0] = -1;
		for(int i = 1; i <= n; i++) read(str[i]), fa[i] = i;
		read(m);
		int x,y;
		while(m--) {
			read(x), read(y);
			int fx = find(x), fy = find(y);
			if(fx == fy) printf( "-1\n" );
			else {
				str[fx] >>= 1; str[fy] >>= 1;
				int hp1 = merge(ls[fx], rs[fx]);
				int hp2 = merge(ls[fy], rs[fy]);
				ls[fx] = rs[fx] = dis[fx] = 0;
				ls[fy] = rs[fy] = dis[fy] = 0;
				fx = merge(fx, hp1);
				fy = merge(fy, hp2);
				int ans = merge(fx, fy);
				printf( "%d\n", str[ans] );
			}
		}
	}
	return 0;
}

树状数组

线段树

莫队

分块

CDQ分治

平衡树

搜索

DFS

BFS

IDDFS

A*

Alpha-Beta

剪枝

最优性剪枝

可行性剪枝

分支定界

字符串

KMP

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<map>
using namespace std;

const int maxx = 1005;
char a[maxx],b[maxx];
int lena,lenb,tot;
int nxt[maxx],ans[maxx];

void calcnext() {
	int i = 0, j = -1;
	int lenb = strlen(b);
	nxt[0] = -1;
	while(i < lenb)
		if(j == -1 || b[i] == b[j]) nxt[++i] = ++j;
		else j = nxt[j];
}

void kmp() {
	int i = 0, j = 0;
	int lena = strlen(a);
	int lenb = strlen(b);
	while(i < lena) {
		if(j == -1 || a[i] == b[j]) {
			i++, j++;
			if(j == lenb) ans[++tot] = i-j, j = nxt[j];
		}
		else j = nxt[j];
	}
}

int main() {
	scanf("%s", a);
	scanf("%s", b);
	calcnext();
	kmp();
	for(int i = 1; i <= tot; i++) cout << ans[i] << " ";
	return 0;
}

Trie

manacher

hash

DP

数位DP

状压DP

区间DP

背包

01

完全

部分

树形DP

期望DP

读入优化

template <class T> inline void read(T &x) {
	int flag = 1; x = 0;
	register char ch = getchar();
	while(ch <  '0' || ch >  '9') { if(ch == '-')  flag = -1; ch = getchar(); }
	while(ch >= '0' && ch <= '9') { x = (x<<1)+(x<<3)+ch-'0'; ch = getchar(); }
	x *= flag;
}

链式前向星

inline void edge(int x, int y, int z) {
	nxt[++tot] = head[x]; head[x] = tot; w[tot] = z; to[tot] = y;
	nxt[++tot] = head[y]; head[y] = tot; w[tot] = z; to[tot] = x;
}

差分

前缀和

a[i] += a[i-1];
a[i][j] += a[i-1][j]+a[i][j-1]-a[i-1][j-1];

离散化

位运算

hash

高精度

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值