写在前面:
十分对不住看本篇博客的朋友,因为这篇博客是未完全写完的,之后会更新但是不知道是什么时候了,蒟蒻博主已经灰暗的退役了。但还是希望能做出一点微小的贡献,希望能对大家有帮助。
数论
#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.youkuaiyun.com/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.youkuaiyun.com/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];