文章目录

  • 数据结构
    • 树状数组
      • 基础
      • 二维树状数组
      • 逆序对
    • 线段树
    • CDQ分治
  • 树论
    • 树的重心
      • 定义
      • 性质
      • 代码
    • 树的直径
      • 性质
      • 代码
    • LCA
    • 主席树
    • 平衡树
      • 替罪羊树
      • Treap
        • 区间翻转
      • Splay
        • 下标建树
        • 权值建树
    • 并查集
  • 图论
    • Harvel
    • 网络流
      • 最大权闭合子图/最大点权独立集/最小点权覆盖
      • 对偶图
      • MCMF
      • 按时间拆点 分层图
    • 最短路
      • Dijsktra
      • SPFA
      • Floyd
    • Tarjan
      • 点双
      • 缩点
      • 割点
    • 2-SAT
    • 最大团
    • 矩阵树定理
      • 无向图的生成树个数
  • 计算几何
    • 凸包
    • 旋转卡壳
      • N个点求最大四边形面积 O(N^2)
    • 扫描线
      • 求二维平面线段划分平面数
      • N个矩形的面积并
  • 数论
    • 组合数预处理
    • 高斯消元
    • gcd & exgcd
    • 求行列式
    • 组合数性质
    • Catalan数
    • Fabonacci数列
    • 常用数学公式
      • 三角函数
      • 数列
  • STL函数
    • Bitset
    • String
    • Set
  • 其他
    • 宏定义
    • 高精度

数据结构

树状数组

基础

struct BIT
{ll c[MAXN];void clear() {mst(c, 0);}int lowbit(int x) {return x & (-x);} //最低一位1void update(int x, ll t) {for(; x < MAXN; x += lowbit(x)) c[x] += t;} ll query(ll x) {ll res = 0; for(; x; x -= lowbit(x)) res += c[x]; return res;}
}bit;

二维树状数组

struct TWO_DBIT
{static const int MAXN = 333;ll c[MAXN][MAXN];void init() {mst(c, 0);}int lowbit(int x) {return x & (-x);}void update(int x, int y, ll k, int N, int M) {for(int i = x; i <= N; i += lowbit(i))for(int j = y; j <= M; j += lowbit(j)) c[i][j] += k;}ll query(int x, int y){ll res = 0;for(int i = x; i; i -= lowbit(i)) for(int j = y; j; j -= lowbit(j)) res += c[i][j];return res;}
};

逆序对

可处理元素重复的情况,update范围在[x,n][x,n][x,n]

struct SF
{   int pos, num;bool operator < (const SF& a) const {if(a.num==num) return a.pos>pos;return a.num < num;}
}a[MAXN];
ll cal()
{ll res = 0; bit.clear(); rep(i, 1, n + 1) a[i].num = b[i], a[i].pos = i; sort(a + 1, a + n + 1);ll cnt = 1;rep(i, 1, n + 1){res += bit.query(a[i].pos - 1);bit.update(a[i].pos, 1);if(a[i].num == a[i - 1].num) cnt++;} return res;
}

线段树

#define ls (x << 1)
#define rs (x << 1 | 1)
const int MAXN = 2e6 + 11, INF = 1e6;
int a[MAXN], b[MAXN]; ll ans;
struct SF {int l, r; ll sum, mx;}seg[MAXN << 2];
void build(int x, int l, int r)
{if(l == r) {seg[x].mx = l * 1ll; return;}int mid = (l + r) >> 1;build(ls, l, mid); build(rs, mid + 1, r); seg[x].sum = seg[ls].sum + seg[rs].sum;seg[x].mx = max(seg[rs].sum + seg[ls].mx, seg[rs].mx);
}
void update(int x, int l, int r, int t, ll d)
{if(l == r){seg[x].mx += d, seg[x].sum += d;return;}int mid = (l + r) >> 1;if(t <= mid) update(ls, l, mid, t, d); else update(rs, mid + 1, r, t, d);seg[x].sum = seg[ls].sum + seg[rs].sum;seg[x].mx = max(seg[rs].sum + seg[ls].mx, seg[rs].mx);
}
ll query(int x, int l, int r, int t)
{if(r <= t) return ans = max(seg[x].sum + ans, seg[x].mx);int mid = (l + r) >> 1;query(ls, l, mid, t);if(t > mid) query(rs, mid + 1, r, t);return ans;
}

CDQ分治

P3810 三维偏序

int n, k, cnt;
const int MAXN = 2e5 + 11;
int c[MAXN], ans[MAXN];
struct SF
{int a, b, c, num, f;
}tmp[MAXN], nod[MAXN];
int lowbit(int x) {return x & (-x);}
bool cmp(SF x, SF y)
{if(x.a != y.a) return x.a < y.a;if(x.b != y.b) return x.b < y.b;return x.c < y.c;
}
void update(int x, int t)
{for(; x <= k; x += lowbit(x)) c[x] += t;
}
int query(int x)
{int res = 0;for(; x; x -= lowbit(x)) res += c[x];return res;
}
void CDQ(int l, int r)
{if(l == r) return;int mid = (l + r) >> 1;CDQ(l, mid); CDQ(mid + 1, r);int p = l, q = mid + 1, tot = l;while(p <= mid && q <= r){if(nod[p].b <= nod[q].b) update(nod[p].c, nod[p].num), tmp[tot++] = nod[p++];else nod[q].f += query(nod[q].c), tmp[tot++] = nod[q++];}while(p <= mid) update(nod[p].c, nod[p].num), tmp[tot++] = nod[p++];while(q <= r) nod[q].f += query(nod[q].c), tmp[tot++] = nod[q++];rep(i, l, mid) update(nod[i].c, -nod[i].num); rep(i, l, r) nod[i] = tmp[i];
}
int main()
{n = re, k = re; cnt = 1;rep(i, 1, n) nod[i].a = re, nod[i].b = re, nod[i].c = re, nod[i].num = 1;sort(nod + 1, nod + n + 1, cmp);rep(i, 2, n){if(nod[i].a == nod[cnt].a && nod[i].b == nod[cnt].b && nod[i].c == nod[cnt].c) nod[cnt].num++;else nod[++cnt] = nod[i];}CDQ(1, cnt); rep(i, 1, cnt) ans[nod[i].f + nod[i].num - 1] += nod[i].num; rep(i, 0, n - 1) printf("%d\n", ans[i]); return 0;
}

树论

树的重心

定义

​ 找到一个点,使得把树变成以该点为根的有根树时,最大子树的结点数最小。换句话说,删除这个点后最大连通块(一定是树)的结点数最小。

性质

  • 一棵树最多有两个重心,且相邻。

  • 删除重心后所得的所有子树,节点数不超过原树的1/2

  • 一棵树添加或者删除一个节点,树的重心最多只移动一条边的位置。

  • 把两棵树通过一条边相连,新的树的重心在原来两棵树重心的路径上。

  • 树中所有点到某个点的距离和中,到重心的距离和是最小的,如果有两个重心,则他们的距离和相等

代码

void init() {r1 = r2 = 0; rep(i, 0, n + 1) edg[i].clear(), son[i] = 0, siz[i] = 1;}
void dfs(int u, int fa)
{for(int v : edg[u]){if(v == fa) continue;dfs(v, u); siz[u] += siz[v];son[u] = max(son[u], siz[v]);} son[u] = max(son[u], n - siz[u]);if((son[u] << 1) <= n) r2 = r1, r1 = u;
}

树的直径

性质

  • 直径两端点一定是两个叶子节点

  • 若一棵树存在多条直径,那么这些直径交于一点且交点是这些直径的中点

  • 对于一棵树,如果在一个点的上接一个叶子节点,那么最多会改变直径的一个端点

  • 距离任意点最远的点一定是直径的一个端点,这个基于贪心求直径方法的正确性可以得出

  • 对于两棵树,如果第一棵树直径两端点为(u,v),第二棵树直径两端点为(x,y),用一条边将两棵树连接,那么新树的直径一定是u,v,x,y中的两个点

代码

void init() {maxl = 0; rep(i, 1, n) dis[i] = 0;}
void dfs(int u, int fa, int fl)
{for(int i = hed[u]; i; i = edg[i].nxt){int v = edg[i].to;if(v == fa) continue;dis[v] = dis[u] + edg[i].val; dfs(v, u, fl); if(dis[v] > maxl) maxl = dis[v], d[fl] = v;}
}
int work()
{n = re; rep(i, 2, n) {int x = re, y = re, c = re;add_edge(x, y, 1ll * c);}dis[1] = 0; dfs(1, -1, 0); init();  dis[d[0]] = 0; dfs(d[0], -1, 1);return printf("%lld\n", dis[d[1]]);
}

LCA

struct LCA
{static const int MAXN = 5e5 + 11;int rt, cnt; int dep[MAXN], hed[MAXN], fa[MAXN][33];struct SF{int to, nxt;}edg[MAXN << 1];void add_edge(int x, int y){edg[++cnt].to = y; edg[cnt].nxt = hed[x]; hed[x] = cnt;edg[++cnt].to = x; edg[cnt].nxt = hed[y]; hed[y] = cnt;}void init(int N){for(int j = 1; (1 << j) <= N; j++) rep(i, 1, N) fa[i][j] = fa[fa[i][j - 1]][j - 1]; }   void dfs(int u, int f){for(int i = hed[u]; i; i = edg[i].nxt){int v = edg[i].to; if(v == f) continue;dep[v] = dep[u] + 1; fa[v][0] = u; dfs(v, u);}}int lca(int a, int b){if(dep[a] < dep[b]) swap(a, b);int tmp = dep[a] - dep[b];for(int i = 0; tmp; i++, tmp >>= 1) if(tmp & 1) a = fa[a][i];if(a == b) return a;per(i, 19, 0) if(fa[a][i] != fa[b][i]) a = fa[a][i], b = fa[b][i];return fa[a][0];}
};

主席树

vector <int> vec;
int getid(int x) {return lower_bound(vec.begin(), vec.end(), x) - vec.begin() + 1;}
struct SF
{int l, r, sum;
}hjt[MAXN * 50];
void insert(int l, int r, int pre, int &now, int p)
{hjt[now = ++cnt] = hjt[pre], hjt[now].sum++; if(l == r) return;int mid = (l + r) >> 1;if(p <= mid) insert(l, mid, hjt[pre].l, hjt[now].l, p); else insert(mid + 1, r, hjt[pre].r, hjt[now].r, p);
}
int query(int l, int r, int L, int R, int k)
{ if(l == r) return l;int mid = (l + r) >> 1, tmp = hjt[hjt[R].l].sum - hjt[hjt[L].l].sum;if(k <= tmp) return query(l, mid, hjt[L].l, hjt[R].l, k);else return query(mid + 1, r, hjt[L].r, hjt[R].r, k - tmp);
}
int main()
{n = re, m = re;rep(i, 1, n) vec.pb(a[i] = re);sort(vec.begin(), vec.end()); vec.erase(unique(vec.begin(), vec.end()), vec.end());rep(i, 1, n) insert(1, n, rt[i - 1], rt[i], getid(a[i]));rep(i, 1, m){int l = re, r = re, k = re;printf("%d\n", vec[query(1, n, rt[l - 1], rt[r], k) - 1]);}return 0;
}

平衡树

替罪羊树

支持前驱后继的查询

struct SCAPAGOAT
{int cnt, root;vector <int> vec;struct SF{int l, r, vlu, tot, fac; bool exi;}spg[MAXN]; void newnode(int &id, int w){id = ++cnt, spg[id].fac = spg[id].tot = 1;spg[id].exi = 1, spg[id].vlu = w;}void update(int id, int g){if(!id) return;if(spg[g].vlu < spg[id].vlu) update(spg[id].l, g);else update(spg[id].r, g);spg[id].tot = spg[spg[id].l].tot + spg[spg[id].r].tot + 1;}void ldr(int id){if(!id) return;ldr(spg[id].l);if(spg[id].exi) vec.push_back(id);ldr(spg[id].r);}void lift(int &id, int l, int r){if(l == r) {id = vec[l]; spg[id].l = spg[id].r = 0;spg[id].fac = spg[id].tot = 1;return;}int mid = (l + r) >> 1;while(l < mid && spg[vec[mid]].vlu == spg[vec[mid - 1]].vlu) mid--;id = vec[mid];if(l < mid) lift(spg[id].l, l, mid - 1); else spg[id].l = 0;lift(spg[id].r, mid + 1, r);spg[id].tot = spg[spg[id].l].tot + spg[spg[id].r].tot + 1;spg[id].fac = spg[spg[id].l].fac + spg[spg[id].r].fac + 1;}void rebuild(int &id){vec.clear(); ldr(id);if(vec.empty()) {id = 0; return;}lift(id, 0, vec.size() - 1);}bool balence(int id){if(max(spg[spg[id].l].tot, spg[spg[id].r].tot) > spg[id].tot * 0.75|| (spg[id].tot - spg[id].fac) > spg[id].tot * 0.3) return 0;return 1;}void check(int &id, int g){if(id == g) return;if(!balence(id)) {rebuild(id); update(root, id); return;}if(spg[g].vlu < spg[id].vlu) check(spg[id].l, g); else check(spg[id].r, g);}void insert(int &id, int w){if(!id){newnode(id, w);check(root, id); return;}spg[id].fac++, spg[id].tot++;if(w < spg[id].vlu) insert(spg[id].l, w);else insert(spg[id].r, w);}void delet(int id, int w){if(spg[id].exi && spg[id].vlu == w) {spg[id].fac--, spg[id].exi = 0;check(root, id); return;   } spg[id].fac--;if(w < spg[id].vlu) delet(spg[id].l, w);else delet(spg[id].r, w);}int getrank(int w){int id = root, res = 1;while(id){if(w <= spg[id].vlu) id = spg[id].l;else {res += spg[spg[id].l].fac + spg[id].exi;id = spg[id].r;}}return res;}int getnum(int rk){int id = root;while(id){if(spg[id].exi && spg[spg[id].l].fac + spg[id].exi == rk) break;else if(spg[spg[id].l].fac >= rk) id = spg[id].l;else rk -= spg[spg[id].l].fac + spg[id].exi, id = spg[id].r;}return spg[id].vlu;}
}spg;

Treap

区间翻转
mt19937 rnd(233);
const int MAXN = 1e5 + 11;
int n, m, cnt, root, a, b, c;
struct SF
{bool rev;int l, r, val, key, siz;
}fhq[MAXN];
int newnode(int w)
{fhq[++cnt].val = w, fhq[cnt].key = rnd();fhq[cnt].siz = 1; fhq[cnt].rev = 0; return cnt;
}
void update(int now) {fhq[now].siz = fhq[fhq[now].l].siz + fhq[fhq[now].r].siz + 1;}
void pushdown(int now)
{swap(fhq[now].l, fhq[now].r);fhq[fhq[now].l].rev ^= 1; fhq[fhq[now].r].rev ^= 1;fhq[now].rev = 0;
}
void split(int now, int siz, int &x, int &y)
{if(!now) {x = y = 0; return;}if(fhq[now].rev) pushdown(now);if(fhq[fhq[now].l].siz < siz) x = now, split(fhq[now].r, siz - fhq[fhq[now].l].siz - 1, fhq[now].r, y);else y = now, split(fhq[now].l, siz, x, fhq[now].l);update(now);
}
int merge(int x, int y)
{if(!x || !y) return x + y;if(fhq[x].key < fhq[y].key){if(fhq[x].rev) pushdown(x);fhq[x].r = merge(fhq[x].r, y);update(x); return x;}else {if(fhq[y].rev) pushdown(y);fhq[y].l = merge(x, fhq[y].l);update(y); return y;}
}
void reverse(int l, int r)
{int x, y, z;split(root, l - 1, x, y);split(y, r - l + 1, y, z);fhq[y].rev ^= 1; root = merge(merge(x, y), z);
}
void ldr(int now)
{if(!now) return;if(fhq[now].rev) pushdown(now);ldr(fhq[now].l); printf("%d ", fhq[now].val); ldr(fhq[now].r);
}
int work()
{rep(i, 1, n) root = merge(root, newnode(i));rep(i, 1, m) {int x = re, y = re;reverse(x, y);}ldr(root); return puts("");
}

Splay

下标建树

洛谷P3391 文艺平衡树

struct SPLAY_INDEX
{int cnt = 0, rt = 0; const int MAXN = 1e6 + 11;struct SF{int son[2], fa, siz, val, flag;}spl[MAXN];void update(int now) {spl[now].siz = spl[spl[now].son[0]].siz + spl[spl[now].son[1]].siz + 1;} void UP(int now) {while(now) update(now), now = spl[now].fa;}void newnode(int &now, int fa, int val){spl[now = ++cnt].val = val; spl[now].fa = fa;spl[now].siz = 1; spl[now].son[0] = spl[now].son[1] = spl[now].flag = 0;  }void build(int &now, int fa, int l, int r){int mid = (l + r) >> 1; newnode(now, fa, mid);if(l < mid) build(spl[now].son[0], now, l, mid - 1);if(r > mid) build(spl[now].son[1], now, mid + 1, r);update(now);}void down(int now){if(spl[now].flag){spl[now].flag = 0;swap(spl[now].son[0], spl[now].son[1]); if(spl[now].son[0]) spl[spl[now].son[0]].flag ^= 1;if(spl[now].son[1]) spl[spl[now].son[1]].flag ^= 1;}}bool check(int now, int fa) {return spl[fa].son[1] == now;}void connect(int now, int fa, int fl) {spl[fa].son[fl] = now; spl[now].fa = fa;}void rotate(int now){int f = spl[now].fa, g = spl[f].fa, fl = check(now, f);connect(spl[now].son[fl ^ 1], f, fl);connect(now, g, check(f, g)); connect(f, now, fl ^ 1);update(f); update(now);    }   void splaying(int now, int gl){if(!gl) rt = now;while(spl[now].fa != gl){int f = spl[now].fa, g = spl[f].fa;if(g != gl) check(now, f) ^ check(f, g)? rotate(now) : rotate(f);rotate(now);}}int getnum(int rk){int now = rt;while(1){down(now); if(rk <= spl[spl[now].son[0]].siz) now = spl[now].son[0];else if(rk <= spl[spl[now].son[0]].siz + 1) {splaying(now, 0); return spl[now].val;}else rk -= spl[spl[now].son[0]].siz + 1, now = spl[now].son[1];}}int getrank(int w){int now = rt;while(now){down(now);if(w <= spl[spl[now].son[0]].siz) now = spl[now].son[0];else if(w <= spl[spl[now].son[0]].siz + 1) return now;else w -= spl[spl[now].son[0]].siz + 1, now = spl[now].son[1];}    }void reverse(int l, int r){if(l >= r) return;int x = getrank(l - 1), y = getrank(r + 1);splaying(x, 0); splaying(y, x);spl[spl[y].son[0]].flag ^= 1;}
}splay;

对于每个需要翻转的区间,应对 (l + 1, r + 1) 进行操作

权值建树
struct SPLAY_VALUE
{int cnt, rt;struct SF {int son[2], fa, siz, val, cnt; }spl[MAXN];void update(int now) {spl[now].siz = spl[spl[now].son[0]].siz + spl[spl[now].son[1]].siz + spl[now].cnt;}bool check(int now, int fa) {return spl[fa].son[1] == now;}void connect(int now, int fa, int fl) {spl[fa].son[fl] = now; spl[now].fa = fa;}void newnode(int &now, int fa, int val){spl[now = ++cnt].val = val; spl[now].fa = fa;spl[now].cnt = spl[now].siz = 1;}void rotate(int now){int f = spl[now].fa, g = spl[f].fa, fl = check(now, f);connect(spl[now].son[fl ^ 1], f, fl); connect(now, g, check(f, g)); connect(f, now, fl ^ 1);update(f); update(now); }void splaying(int now, int gl){if(!gl) rt = now;while(spl[now].fa != gl){int f = spl[now].fa, g = spl[f].fa;if(g != gl) check(now, f) ^ check(f, g)? rotate(now) : rotate(f); rotate(now);}} void delnode(int now){splaying(now, 0);if(spl[now].cnt > 1) spl[now].cnt--;else if(spl[now].son[1]){int p = spl[now].son[1];while(spl[p].son[0]) p = spl[p].son[0];splaying(p, now);connect(spl[now].son[0], p, 0);rt = p; spl[p].fa = 0; update(rt); }else rt = spl[now].son[0], spl[rt].fa = 0;}void delet(int w, int now){if(w == spl[now].val) delnode(now);else if(w < spl[now].val) delet(w, spl[now].son[0]);else delet(w, spl[now].son[1]);}void insert(int w, int &now, int fa){if(!now) newnode(now, fa, w), splaying(now, 0);else if(w < spl[now].val) insert(w, spl[now].son[0], now);else if(w > spl[now].val) insert(w, spl[now].son[1], now);else spl[now].cnt++, splaying(now, 0);}int getnum(int rk){int now = rt;while(now){int lsize = spl[spl[now].son[0]].siz;if(lsize + 1 <= rk && rk <= lsize + spl[now].cnt){splaying(now, 0);return spl[now].val;}else if(lsize >= rk) now = spl[now].son[0];else rk -= lsize + spl[now].cnt, now = spl[now].son[1];}}int getrank(int w){int now = rt, rk = 1;while(now){if(spl[now].val == w) {rk += spl[spl[now].son[0]].siz;splaying(now, 0); break;}if(w <= spl[now].val) now = spl[now].son[0];else rk += spl[spl[now].son[0]].siz + spl[now].cnt, now = spl[now].son[1];}return rk; }
}splay;

查询前驱splay.getnum(splay.getrank(x) - 1)

查询后继splay.getnum(splay.getrank(x + 1))

并查集

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

图论

Harvel

给定所有点度数,判断能否构成简单图

flag = 1, n = read();
for(int i = 1; i <= n; i++) a[i] = read();
sort(a + 1, a + n + 1, cmp);
for(int i = 1; i <= n; i++)
{sort(a + i + 1, a + n + 1, cmp); if(i + a[i] > n || a[i] < 0) {flag = 0; break;} for(int j = 1; j <= a[i]; j++) a[i + j]--;
}
puts(!flag? "no" : "yes");

网络流

最大权闭合子图/最大点权独立集/最小点权覆盖

struct DICNIC
{int st, gl, cnt, sum;int hed[MAXN], lel[MAXN], cur[MAXN];struct SF {int to, nxt; ll cap;}edg[MAXM << 1];void add_edge(int x, int y, ll c){edg[++cnt].to = y; edg[cnt].cap = c; edg[cnt].nxt = hed[x]; hed[x] = cnt;edg[++cnt].to = x; edg[cnt].cap = 0; edg[cnt].nxt = hed[y]; hed[y] = cnt;}void init(){st = sum = 0; cnt = -1; gl = m + n + 1; rep(i, 0, gl) hed[i] = -1;}bool bfs(){queue <int> Q; rep(i, st, gl) lel[i] = 0;int u, v; Q.push(st); lel[st] = 1;while(!Q.empty()){int u = Q.front(); Q.pop();for(int i = hed[u]; ~i; i = edg[i].nxt){v = edg[i].to;if(!lel[v] && edg[i].cap > 0) {lel[v] = lel[u] + 1; Q.push(v);}}}return (lel[gl]);}ll dfs(int u, ll flow){if(u == gl) return flow;int v; ll nflow = 0, tmp;for(int &i = cur[u]; ~i; i = edg[i].nxt){v = edg[i].to;if(lel[v] == lel[u] + 1 && edg[i].cap > 0){tmp = dfs(v, min(flow, edg[i].cap));flow -= tmp, edg[i].cap -= tmp;nflow += tmp, edg[i ^ 1].cap += tmp;if(!flow) break;}}if(!flow) lel[u] = 0;return nflow;}ll dicnic(){ll tmp, res = 0;while(bfs()){rep(i, st, gl) cur[i] = hed[i];while(tmp = dfs(st, INF)) res += tmp;}return res;}
}dic;

对偶图

ICPC-Beijing2006狼抓兔子 诸如此类不相交的图(常见于网格图)求最小割,当数据规模较大时可转成对偶图求解

struct SF
{int to, nxt, vlu;
}grf[3 * MAXN];
struct SFes
{int id, vlu;friend bool operator <(const SFes &a, const SFes &b){return a.vlu > b.vlu;}
};
priority_queue <SFes> Q;
void add(int x, int y, int v)
{grf[++cnt].to = y; grf[cnt].nxt = hed[x]; grf[cnt].vlu = v; hed[x] = cnt;grf[++cnt].to = x; grf[cnt].nxt = hed[y]; grf[cnt].vlu = v; hed[y] = cnt;
}
void dij(int s)
{dis[s] = 0;SFes u, v;u.id = s, u.vlu = 0;Q.push(u);while(!Q.empty()){u = Q.top(); Q.pop();mark[u.id] = 1;for(int i = hed[u.id]; i; i = grf[i].nxt){v.id = grf[i].to;if(!mark[v.id] && dis[v.id] > u.vlu + grf[i].vlu){v.vlu = dis[v.id] = u.vlu + grf[i].vlu;Q.push(v);}}}
}
int main()
{n = re, m = re; mst(dis, 0x7f);rep(i, 1, n){ rep(j, 1, m - 1){int x, y, c = re;if(i == 1) x = 1, y = j * 2 + 1;else if(i == n) x = (n - 1) * (m - 1) * 2 + 2, y = ((i - 2) * (m - 1) + j) * 2;else x = ((i - 2) * (m - 1) + j) * 2, y = ((i - 1) * (m - 1) + j) * 2 + 1;add(x, y, c);}}rep(i, 1, n - 1){rep(j, 1, m){int x, y, c = re;if(j == 1) x = (n - 1) * (m - 1) * 2 + 2, y = ((i - 1) * (m - 1) + j) * 2;else if(j == m) x = 1, y = ((i - 1) * (m - 1) + j - 1) * 2 + 1;else x = ((i - 1) * (m - 1) + j - 1) * 2 + 1, y = ((i - 1) * (m - 1) + j) * 2;add(x, y, c);}}rep(i, 1, n - 1){rep(j, 1, m - 1){int x, y, c = re;x = ((i - 1) * (m - 1) + j) * 2, y = ((i - 1) * (m - 1) + j) * 2 + 1;add(x, y, c);}}n = (n - 1) * (m - 1) * 2 + 2;dij(1); printf("%d\n", dis[n]);return 0;
}

MCMF

struct MCMF
{int st, gl, cnt; ll mflow, mcost;int pre[MAXN], hed[MAXN], mark[MAXN], cost[MAXN];struct SF{int u, v, nxt; ll cap, val;}edg[MAXM << 1];void init(int x) {cnt = -1, st = 0, gl = x * 2 + 1;rep(i, 0, gl) hed[i] = -1;}   void add_edge(int x, int y, int c, int v){ edg[++cnt].u = x, edg[cnt].v = y, edg[cnt].cap = c, edg[cnt].val = v, edg[cnt].nxt = hed[x], hed[x] = cnt;edg[++cnt].u = y, edg[cnt].v = x, edg[cnt].cap = 0, edg[cnt].val = -v, edg[cnt].nxt = hed[y], hed[y] = cnt;}bool spfa(){queue <int> Q;rep(i, 0, gl) mark[i] = 0, pre[i] = -1, cost[i] = INF;mark[st] = 1; cost[st] = 0; Q.push(st); while(!Q.empty()){int u = Q.front(); mark[u] = 0; Q.pop(); for(int i = hed[u]; ~i; i = edg[i].nxt){int v = edg[i].v; if(edg[i].cap > 0 && cost[v] > cost[u] + edg[i].val){pre[v] = i; cost[v] = cost[u] + edg[i].val;if(!mark[v]) mark[v] = 1, Q.push(v);}}     }return (~pre[gl]);}ll Mcmf(){ll flow = 0;while(spfa()){mflow = INF; for(int i = pre[gl]; ~i; i = pre[edg[i].u]) mflow = min(mflow, edg[i].cap);flow += mflow; for(int i = pre[gl]; ~i; i = pre[edg[i].u]) edg[i].cap -= mflow, edg[i ^ 1].cap += mflow;mcost += mflow * cost[gl];}return mcost;}
}mcmf;

按时间拆点 分层图

网络流可按时间拆点建图。

P2754 家园/星际转移问题

最短路

Dijsktra

默认是双向边,还有起点终点记得改。

struct DIJSKTRA
{int st, gl, cnt; int hed[MAXN], mark[MAXN]; ll dis[MAXN];struct SF{int to, nxt; ll val;}edg[MAXM << 1];struct SFes{int id; ll dist;bool operator <(const SFes &a) const{return a.dist < dist;}};void add_edge(int x, int y, ll c){edg[++cnt].to = y; edg[cnt].val = c; edg[cnt].nxt = hed[x]; hed[x] = cnt;edg[++cnt].to = x; edg[cnt].val = c; edg[cnt].nxt = hed[y]; hed[y] = cnt;}void init(){st = cnt = 0, gl = n;rep(i, 1, n) dis[i] = INF, mark[i] = 0;}void dijkstra(){SFes u, v;u.id = st, u.dist = 0; dis[u.id] = 0; priority_queue <SFes> Q; Q.push(u);while(!Q.empty()){u = Q.top(); Q.pop();if(mark[u.id]) continue; mark[u.id] = 1;for(int i = hed[u.id]; i; i = edg[i].nxt){v.id = edg[i].to; if(dis[v.id] > dis[u.id] + edg[i].val){v.dist = dis[v.id] = dis[u.id] + edg[i].val;Q.push(v);}}}}
}dij;

SPFA

struct SPFA
{queue <int> Q;int st, gl, cnt; int hed[MAXN], mark[MAXN]; ll dis[MAXN];struct SF{int to, nxt; ll val;}edg[MAXM << 1];void add_edge(int x, int y, ll c){edg[++cnt].to = y; edg[cnt].val = c; edg[cnt].nxt = hed[x]; hed[x] = cnt;edg[++cnt].to = x; edg[cnt].val = c; edg[cnt].nxt = hed[y]; hed[y] = cnt;}void init(){cnt = 0; st = 0, gl = n + 1;rep(i, 1, n) hed[i] = mark[i] = 0, dis[i] = INF;}void spfa(){int u, v; Q.push(st); mark[st] = 1, dis[st] = 0;while(!Q.empty()){u = Q.front(); mark[u] = 0; Q.pop();for(int i = hed[u]; i; i = edg[i].nxt){v = edg[i].to;if(dis[v] > dis[u] + edg[i].val){dis[v] = dis[u] + edg[i].val;if(!mark[v]) Q.push(v);}}}}
}spfa;

Floyd

int floyd()
{for(int k = 1; k <= n; k++)for(int i = 1; i <= n; i++)for(int j = 1; j <= n; j++)if(dis[i][j] < dis[i][k] * dis[k][j])dis[i][j] = dis[i][k] * dis[k][j];for(int i = 1; i <= n; i++)if(dis[i][i] > 1) return 1;return 0;
}

Tarjan

点双

缩点

struct TARJAN
{static const int MAXM = 5e4 + 11, MAXN = 1e4 + 11; int tp, cnt, num, ring;struct SF{int to, nxt;}edg[MAXM << 1];int hed[MAXN], sta[MAXN], low[MAXN], dfn[MAXN], anti[MAXN], insta[MAXN], belong[MAXN], rnum[MAXN];void add_edge(int x, int y){edg[++cnt].to = y; edg[cnt].nxt = hed[x]; hed[x] = cnt;edg[++cnt].to = x; edg[cnt].nxt = hed[y]; hed[y] = cnt;}void init(int N = MAXN){cnt = num = tp = ring = 0;rep(i, 0, N) hed[i] = belong[i] = low[i] = dfn[i] = insta[i] = rnum[i] = 0;}void dfs(int u){dfn[u] = low[u] = ++num; sta[++tp] = u; insta[u] = 1;for(int i = hed[u]; i; i = edg[i].nxt){int v = edg[i].to;if(!dfn[v]) dfs(v), low[u] = min(low[u], low[v]);else if(insta[v]) low[u] = min(low[u], dfn[v]);}if(dfn[u] == low[u]){int v = -1; ring++;while(u != v){v = sta[tp--];++rnum[ring];belong[v] = ring;}}}void rebuild(int N){rep(u, 1, N)for(int i = hed[u]; i; i = edg[i].nxt)if(belong[u] != belong[edg[i].to]) anti[belong[u]]++; }void tarjan(int N) {rep(i, 1, N) if(!dfn[i]) dfs(i);}
}tj;

割点

2-SAT

最大团

矩阵树定理

无向图的生成树个数

例题:bzoj4031小z的房间

有时部分情况需要特判一下,不能纯贴板子quq

int mov[5][5] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
int det(int x)
{rep(i, 1, x) rep(j, 1, x) a[i][j] = (a[i][j] + MOD) % MOD;ll res = 1, f = 1;rep(i, 1, x){rep(j, i + 1, x){ll A = a[i][i], B = a[j][i];while(B){ll tmp = A / B; A %= B; swap(A, B);rep(k, i, x) a[i][k] = (a[i][k] - tmp * a[j][k] % MOD + MOD) % MOD;rep(k, i, x) swap(a[i][k], a[j][k]); f = -f;} }if(!a[i][i]) return 0;res = (res * a[i][i]) % MOD;}if(f == -1) return (MOD - res) % MOD;return res;
}
int main()
{n = re, m = re;rep(i, 1, n) scanf("%s", str[i] + 1);rep(i, 1, n) rep(j, 1, m) if(str[i][j] == '.') p[i][j] = ++cnt;rep(i, 1, n){rep(j, 1, m){if(str[i][j] == '.'){rep(k, 0, 3){int nx = i + mov[k][0], ny = j + mov[k][1];if(nx < 1 || ny < 1 || nx > n || ny > m || str[nx][ny] != '.') continue;int u = p[i][j], v = p[nx][ny];a[u][v]--, a[u][u]++;}}}} printf("%d\n", det(cnt - 1)); //!!!不要忘记cnt-1return 0;
}
  • 2.给出有向图和其中的一个点,求以这个点为根的生成外向树个数。

  • 3.给出有向图和其中一个点,求以这个点为根的生成内向树个数。

计算几何

凸包

struct SF
{double x, y;SF(double x = 0, double y = 0) : x(x), y(y){};
}grf[MAXN], sta[MAXN];
int sgn(double a) return (fabs(a) < eps)? 0 : (a > 0)? 1 : -1;
bool operator <(const SF& a, const SF& b)
{return (!sgn(a.x - b.x))? a.y < b.y : a.x < b.x;
}
SF operator -(SF a, SF b)
{return SF(a.x - b.x, a.y - b.y);
}
double cross(SF a, SF b)
{return (a.x * b.y - b.x * a.y);
}
double turn(SF a, SF b, SF nw)
{SF A = b - a;SF B = nw - a;return cross(A, B);
}
double length(SF a, SF b)
{return sqrt((b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y));
}
void convexhull()
{ans = 0;sort(grf + 1, grf + n + 1);sta[0] = grf[1], sta[1] = grf[2];int top = 1;for(int i = 3; i <= n; i++){while(top && turn(sta[top - 1], sta[top], grf[i]) <= 0) top--;sta[++top] = grf[i];}for(int i = n - 1, tmp = top; i >= 1; i--){while(top > tmp && turn(sta[top - 1], sta[top], grf[i]) <= 0) top--;sta[++top] = grf[i];}for(int i = 1; i <= top; i++) ans += length(sta[i - 1], sta[i]);
}

旋转卡壳

N个点求最大四边形面积 O(N^2)

struct SF
{ll x, y;SF(ll x = 0, ll y = 0) : x(x), y(y){};
}p[MAXN], s[MAXN];
int sgn(ll a){return ((abs(a) < eps)? 0 : ((a > 0)? 1 : -1));}
bool operator <(const SF &a, const SF &b)
{return (!sgn(a.x - b.x))? a.y < b.y : a.x < b.x;
}
SF operator -(SF a, SF b)
{return SF(a.x - b.x, a.y - b.y);
}
ll operator *(SF a, SF b)
{return (a.x * b.y - b.x * a.y);
}
ll turn(SF a, SF b, SF nw)
{SF A = b - a, B = nw - a;return A * B;
}
ll convexhull()
{ll ans = 0;sort(p + 1, p + n + 1);int top = 1; s[0] = p[1], s[1] = p[2];for(int i = 3; i <= n; i++){while(top && turn(s[top - 1], s[top], p[i]) < 0) top--; //此处共线的点也应算入s[++top] = p[i];}for(int i = n - 1, tmp = top; i >= 1; i--){while(top > tmp && turn(s[top - 1], s[top], p[i]) < 0) top--;s[++top] = p[i];} s[top + 1] = p[1];if(top <= 2) return 0ll;else if(top == 3) //不保证为凸四边形,三个点的情况特殊讨论{ll res = INF; ans = abs((s[2] - s[1]) * (s[3] - s[1])); rep(i, 1, n){ll t1 = abs((s[2] - s[1]) * (p[i] - s[1])), t2 = abs((s[2] - s[3]) * (p[i] - s[3])), t3 = abs((s[3] - s[1]) * (p[i] - s[1]));if(t1) res = min(res, t1); if(t2) res = min(res, t2); if(t3) res = min(res, t3);}return ans - res; } rep(i, 1, top){int a = i % top + 1, b = (i + 2) % top + 1;rep(j, i + 2, top){while((a % top + 1) != j && abs((s[j] - s[i]) * (s[a + 1] - s[i])) > abs((s[j] - s[i]) * (s[a] - s[i]))) a = a % top + 1;while((b % top + 1) != i && abs((s[j] - s[i]) * (s[b + 1] - s[i])) > abs((s[j] - s[i]) * (s[b] - s[i]))) b = b % top + 1;ans = max(ans, abs((s[j] - s[i]) * (s[a] - s[i])) + abs((s[b] - s[i]) * (s[j] - s[i])));}}return ans;
}

扫描线

求二维平面线段划分平面数

CF1401E. Divide Square

struct SF
{int x, y, op;  bool operator <(const SF& a)const {return x < a.x;}
}seg[MAXN];
struct SFes
{int l, r, x;bool operator <(const SFes& a)const {return x < a.x;}
}lin[MAXN];
int lowbit(int x) {return x & (-x);}
void update(int x, int t) {for(int i = x; i <= INF; i += lowbit(i)) c[i] += t;}
ll query(int x) {ll res = 0; for(int i = x; i; i -= lowbit(i)) res += c[i]; return res;}
int main()
{n = re, m = re; ans = 1ll; rep(i, 1, n) {int y = re, l = re, r = re; ans += (l == 0 && r == INF);seg[++cnt] = {l, y, 1}; seg[++cnt] = {r + 1, y, -1};} rep(i, 1, m) lin[i].x = re, lin[i].l = re, lin[i].r = re, ans += (lin[i].l == 0 && lin[i].r == INF);sort(seg + 1, seg + cnt + 1); sort(lin + 1, lin + m + 1);for(int i = 1, j = 0; i <= m; i++){while(j < cnt && seg[j + 1].x <= lin[i].x) j++, update(seg[j].y + 1, seg[j].op);ans += query(lin[i].r + 1) - query(lin[i].l);}printf("%lld\n", ans);return 0;
}

N个矩形的面积并

洛谷P5490

const int MAXN = 1e6 + 11;
int n, m; ll ans; ll X[MAXN << 1];
struct SF
{ll l, r, h; int fl;bool operator <(const SF &a) const{return h < a.h;}
}seg[MAXN << 1];
struct SFes
{ll len; int l, r, sum;
}tree[MAXN << 2];
void pushup(int now)
{int l = tree[now].l, r = tree[now].r;if(tree[now].sum) tree[now].len = X[r + 1] - X[l];else tree[now].len = tree[now << 1].len + tree[now << 1 | 1].len;
}
void build(int now, int l, int r)
{tree[now].l = l, tree[now].r = r;tree[now].len = tree[now].sum = 0;if(l == r) return;int mid = (l + r) >> 1;build(now << 1, l, mid); build(now << 1 | 1, mid + 1, r);
}
void insert(int now, ll L, ll R, int flag)
{int l = tree[now].l, r = tree[now].r;if(X[r + 1] <= L || X[l] >= R) return;if(X[l] >= L && X[r + 1] <= R){tree[now].sum += flag;pushup(now); return;}insert(now << 1, L, R, flag); insert(now << 1 | 1, L, R, flag); pushup(now);
}
int solve()
{rep(i, 1, n){ll X1 = re, Y1 = re, X2 = re, Y2 = re;X[2 * i - 1] = X1; seg[2 * i - 1] = {X1, X2, Y1, 1};X[2 * i] = X2; seg[2 * i] = {X1, X2, Y2, -1};}n <<= 1; sort(seg + 1, seg + n + 1); sort(X + 1, X + n + 1);m = unique(X + 1, X + n + 1) - X - 1;build(1, 1, m - 1);rep(i, 1, n - 1){insert(1, seg[i].l, seg[i].r, seg[i].fl);ans += tree[1].len * (seg[i + 1].h - seg[i].h);}return printf("%lld\n", ans);
}

数论

组合数预处理

void init_C(int n) {inv[1] = 1;for(int i = 2; i <= n; i++)inv[i] = inv[MOD % i] * (MOD - MOD / i) % MOD;fac[0] = 1, invfac[0] = 1;for(int i = 1; i <= n; i++) {fac[i] = fac[i - 1] * i % MOD;invfac[i] = invfac[i - 1] * inv[i] % MOD;}
}
ll C(ll n, ll m) {if(n < 0 || m < 0 || n - m < 0)return 0;return fac[n] * invfac[n - m] % MOD * invfac[m] % MOD;
}

高斯消元

void Gauss()
{int mx; rep(i, 1, n){mx = i;rep(j, i + 1, n) if(fabs(a[j][i]) > fabs(a[mx][i])) mx = j;if(mx != i) swap(a[mx], a[i]);if(!a[i][i]) {flag = 0; return;}rep(j, 1, n)if(i != j){rep(k, i + 1, n + 1) a[j][k] -= a[i][k] * (a[j][i] / a[i][i]); a[j][i] = 0;}}
}

gcd & exgcd

int gcd(int a, int b){return !b? a : gcd(b, a % b);}
int exgcd(int k, int t, int &x, int &y)
{if(!t) {x = 1, y = 0;return k;}int tmp, g = exgcd(t, k % t, x, y);tmp = y; y = x - k / t * y; x = tmp;return g;
}

求行列式

int det(int x)
{rep(i, 1, x) rep(j, 1, x) a[i][j] = (a[i][j] + MOD) % MOD;ll res = 1, f = 1;rep(i, 1, x){rep(j, i + 1, x){ll A = a[i][i], B = a[j][i];while(B){ll tmp = A / B; A %= B; swap(A, B);rep(k, i, x) a[i][k] = (a[i][k] - tmp * a[j][k] % MOD + MOD) % MOD;rep(k, i, x) swap(a[i][k], a[j][k]); f = -f;} }if(!a[i][i]) return 0;res = (res * a[i][i]) % MOD;}if(f == -1) return (MOD - res) % MOD;return res;
}

组合数性质

  • 组合数取模

Cnmmodp=Cnpmp×CnmodpmmodpmodpC_n^m \mod p=C_{\frac{n}p}^{\frac{m}p}\times C_{n\mod p}^{m\mod p}\mod p Cnm​modp=Cpn​pm​​×Cnmodpmmodp​modp

  • 按行求和

  • 杨辉三角性质
    Cnk+Cnk−1=n!k!(n−k)!+n!(k−1)!(n−k+1)!=n!(n−k+1)+kk!(n−k+1)!=Cn+1kC_n^k+C_n^{k-1}=\frac{n!}{k!(n-k)!}+\frac{n!}{(k-1)!(n-k+1)!}=n!\frac{(n-k+1)+k}{k!(n-k+1)!}=C_{n+1}^k Cnk​+Cnk−1​=k!(n−k)!n!​+(k−1)!(n−k+1)!n!​=n!k!(n−k+1)!(n−k+1)+k​=Cn+1k​

  • 可将变化量 从两个组合数的范围缩小至一个组合数中
    CnrCrk=CnkCn−kr−kC_n^rC_r^k=C_n^kC_{n-k}^{r-k} Cnr​Crk​=Cnk​Cn−kr−k​

  • 就是 个相同的球中不重复地选出 个球的组合数
    Cm+nk=∑i=0kCmiCnk−iC_{m+n}^k=\displaystyle\sum_{i=0}^kC_m^iC_n^{k-i} Cm+nk​=i=0∑k​Cmi​Cnk−i​

  • 化去组合数外的变化量

kCnk=kn!k!(n−k)!=n(n−1)!(k−1)!(n−k)!=nCn−1k−1kC_n^k=k\frac{n!}{k!(n-k)!}=n\frac{(n-1)!}{(k-1)!(n-k)!}=nC_{n-1}^{k-1} kCnk​=kk!(n−k)!n!​=n(k−1)!(n−k)!(n−1)!​=nCn−1k−1​

  • 组合数和2幂次的关系1
    1Cn1+2Cn2+3Cn3+...+nCnn=n2n−11C_n^1+2C_n^2+3C_n^3+...+nC_n^n=n2^{n-1} 1Cn1​+2Cn2​+3Cn3​+...+nCnn​=n2n−1

  • 组合数和2幂次的关系2
    12Cn1+22Cn2+32Cn3+...+n2Cnn=n(n+1)2n−21^2C_n^1+2^2C_n^2+3^2C_n^3+...+n^2C_n^n=n(n+1)2^{n-2} 12Cn1​+22Cn2​+32Cn3​+...+n2Cnn​=n(n+1)2n−2

  • 杨辉三角整行/整列求和性质
    C11+C21+...+Cn1=Cn+12=n∗(n+1)2C_1^1+C_2^1+...+C_n^1=C_{n+1}^2=\frac{n*(n+1)}{2} C11​+C21​+...+Cn1​=Cn+12​=2n∗(n+1)​

    C12+C22+C32+...+Cn2=Cn+13=n(n+1)(n−1)6C_1^2+C_2^2+C_3^2+...+C_n^2=C_{n+1}^3=\frac{n(n+1)(n-1)}{6} C12​+C22​+C32​+...+Cn2​=Cn+13​=6n(n+1)(n−1)​

  • 组合数平方求和

∑i=0n(Cni)2=C2nn\displaystyle\sum_{i=0}^n(C_n^i)^2=C_{2n}^n i=0∑n​(Cni​)2=C2nn​

  • 和差化积(?
    ∑i=k+1nCi−1i−k−1=Cnn−k−1\displaystyle\sum_{i=k+1}^nC_{i-1}^{i-k-1}=C_n^{n-k-1} i=k+1∑n​Ci−1i−k−1​=Cnn−k−1​

Catalan数

若 Cn=∑i=1nCi−1Cn−i,C0=1C_n=\displaystyle\sum_{i=1}^nC_{i-1}C{n-i},C_0=1Cn​=i=1∑n​Ci−1​Cn−i,C0​=1,则我们称 CnC_nCn​ 为第n个Catalan数。

我们知道:其普通生成函数为1−1−4x2x\frac{1-\sqrt{1-4x}}{2x}2x1−1−4x​​ ,求得通项公式为 Cn=C2nnn+1C_n= \frac{C_{2n}^n}{n+1}Cn​=n+1C2nn​​ 。

例:1,2,···,n 这些数字依次压入栈中(可以随时进行pop操作),那么最后将栈中元素弹出直至栈为空可以得到一个出栈序列。所有这样的不同出栈序列数即为 CnC_nCn​ 。

Fabonacci数列

常用数学公式

三角函数

  • 和差角公式
    cos(A±B)=cosAcosB∓sinAsinBsin(A±B)=sinAcosB±cosAsinBtan(A±B)=tanA±tanB1∓tanAtanBcos(A\pm B)=cosAcosB\mp sinAsinB \\ sin(A\pm B)=sinAcosB\pm cosAsinB \\ tan(A\pm B)=\frac{tanA\pm tanB}{1\mp tanAtanB} cos(A±B)=cosAcosB∓sinAsinBsin(A±B)=sinAcosB±cosAsinBtan(A±B)=1∓tanAtanBtanA±tanB​

  • 和差化积公式
    sinA±sinB=2sinA±B2cosA∓B2cosA+cosB=2cosA+B2cosA−B2cosA−cosB=−2sinA+B2sinA−B2tanA±tanB=sin(A±B)cosAcosBcotA±cotB=±sin(A±B)sinAsinBsinA\pm sinB=2sin\frac{A\pm B}{2}cos\frac{A\mp B}{2} \\ cosA+cosB=2cos\frac{A+B}{2}cos\frac{A-B}{2} \\ cosA-cosB=-2sin\frac{A+B}{2}sin\frac{A-B}{2} \\ tanA\pm tanB=\frac{sin(A\pm B)}{cosAcosB} \\ cotA\pm cotB=\pm \frac{sin(A\pm B)}{sinAsinB} sinA±sinB=2sin2A±B​cos2A∓B​cosA+cosB=2cos2A+B​cos2A−B​cosA−cosB=−2sin2A+B​sin2A−B​tanA±tanB=cosAcosBsin(A±B)​cotA±cotB=±sinAsinBsin(A±B)​

  • 积化和差公式
    sinAcosB=12[sin(A+B)+sin(A−B)]cosAsinB=12[sin(A+B)−sin(A−B)]cosAcosB=12[cos(A+B)+cos(A−B)]sinAsinB=12[cos(A+B)−cos(A−B)]sinAcosB=\frac{1}{2}[sin(A+B)+sin(A-B)] \\ cosAsinB=\frac{1}{2}[sin(A+B)-sin(A-B)] \\ cosAcosB=\frac{1}{2}[cos(A+B)+cos(A-B)] \\ sinAsinB=\frac{1}{2}[cos(A+B)-cos(A-B)] sinAcosB=21​[sin(A+B)+sin(A−B)]cosAsinB=21​[sin(A+B)−sin(A−B)]cosAcosB=21​[cos(A+B)+cos(A−B)]sinAsinB=21​[cos(A+B)−cos(A−B)]

  • 二倍角公式
    sin2A=2sinAcosAcos2A=2cos2A−1=1−2sin2A=cos2A−sin2Atan2A=2tanA1−tan2Asin2A=2sinAcosA \\ cos2A=2cos^2A-1=1-2sin^2A=cos^2A-sin^2A \\ tan2A=\frac {2tanA}{1-tan^2A} sin2A=2sinAcosAcos2A=2cos2A−1=1−2sin2A=cos2A−sin2Atan2A=1−tan2A2tanA​

数列

  • 等差数列求和

Sn=na1+n(n−1)d2S_n=na_1+\frac{n(n-1)d}{2} Sn​=na1​+2n(n−1)d​

  • 等比数列求和
    Sn=a1(1−qn)1−qS_n=\frac{a_1(1-q^n)}{1-q} Sn​=1−qa1​(1−qn)​

STL函数

Bitset

foo.size() 返回大小(位数)
foo.count() 返回1的个数
foo.any() 返回是否有1
foo.none() 返回是否没有1
foo.set() 全都变成1
foo.set(p) 将第p + 1位变成1
foo.set(p, x) 将第p + 1位变成x
foo.reset() 全都变成0
foo.reset(p) 将第p + 1位变成0
foo.flip() 全都取反
foo.flip(p) 将第p + 1位取反
foo.to_ulong() 返回它转换为unsigned long的结果,如果超出范围则报错
foo.to_ullong() 返回它转换为unsigned long long的结果,如果超出范围则报错
foo.to_string() 返回它转换为string的结果

String

str.size();//返回字符串长度
str.length();//返回字符串长度
str.empty();//检查 str 是否为空,为空返回 1,否则返回 0
str1.swap(str2);//把 str1 与 str2 交换
str.erase(3);//删除 [3] 及以后的字符,并返回新字符串
str.erase(3, 5);//删除从 [3] 开始的 5 个字符,并返回新字符串
str.push_back('a');//在 str 末尾添加字符'a'
str.append("abc");//在 str 末尾添加字符串"abc"
str.insert(2, "sz");//从 [2] 位置开始添加字符串 "sz",并返回形成的新字符串
str.insert(2, "abcd", 3);//从 [2] 位置开始添加字符串 "abcd" 的前 3 个字符,并返回形成的新字符串
str.insert(2, "abcd", 1, 3);//从 [2] 位置开始添加字符串 "abcd" 的前 [2]~[2+(3-1)] 个字符,并返回形成的新字符串
str.replace(2, 4, "sz");//返回把 [2]~[2+(4-1)] 的内容替换为 "sz" 后的新字符串
str.replace(2, 4, "abcd", 3);//返回把 [2]~[2+(4-1)] 的内容替换为 "abcd" 的前3个字符后的新字符串
str.substr(3); //返回 [3] 及以后的子串
str.substr(2, 4); //返回 str[2]~str[2+(4-1)] 子串(即从[2]开始4个字符组成的字符串)
str.find("ab");//返回字符串 ab 在 str 的位置
str.find("ab", 2);//在 str[2]~str[n-1] 范围内查找并返回字符串 ab 在 str 的位置
str.rfind("ab", 2);//在 str[0]~str[2] 范围内查找并返回字符串 ab 在 str 的位置//first 系列函数
str.find_first_of("apple");//返回 apple 中任何一个字符首次在 str 中出现的位置
str.find_first_of("apple", 2);//返回 apple 中任何一个字符首次在 str[2]~str[n-1] 范围中出现的位置
str.find_first_not_of("apple");//返回除 apple 以外的任何一个字符在 str 中首次出现的位置
str.find_first_not_of("apple", 2);//返回除 apple 以外的任何一个字符在 str[2]~str[n-1] 范围中首次出现的位置//last 系列函数
str.find_last_of("apple");//返回 apple 中任何一个字符最后一次在 str 中出现的位置
str.find_last_of("apple", 2);//返回 apple 中任何一个字符最后一次在 str[0]~str[2] 范围中出现的位置
str.find_last_not_of("apple");//返回除 apple 以外的任何一个字符在 str 中最后一次出现的位置
str.find_last_not_of("apple", 2);//返回除 apple 以外的任何一个字符在 str[0]~str[2] 范围中最后一次出现的位置//以上函数如果没有找到,均返回string::npos
cout << string::npos;
string s(str):生成字符串为str的复制品
string s(str, strbegin,strlen):将字符串str中从下标strbegin开始、长度为strlen的部分作为字符串初值
string s(cstr, char_len):以C_string类型cstr的前char_len个字符串作为字符串s的初值
string s(num ,c):生成num个c字符的字符串
string s(str, stridx):将字符串str中从下标stridx开始到字符串结束的位置作为字符串初值

Set

set用法:

begin();            // 返回指向第一个元素的迭代器
end();              // 返回指向迭代器的最末尾处(即最后一个元素的下一个位置)
clear();            // 清除所有元素
count();            // 返回某个值元素的个数
empty();            // 如果集合为空,返回true
equal_range();      //返回集合中与给定值相等的上下限的两个迭代器
erase()–删除集合中的元素
find()–返回一个指向被查找到元素的迭代器
get_allocator()–返回集合的分配器
insert()–在集合中插入元素
lower_bound()–返回指向大于(或等于)某值的第一个元素的迭代器
key_comp()–返回一个用于元素间值比较的函数
max_size()–返回集合能容纳的元素的最大限值
rbegin()–返回指向集合中最后一个元素的反向迭代器
rend()–返回指向集合中第一个元素的反向迭代器
size()–集合中元素的数目
swap()–交换两个集合变量
upper_bound()–返回大于某个值元素的迭代器
value_comp()–返回一个用于比较元素间的值的函数

其他

宏定义

#include <bits/stdc++.h>
#define re read()
#define ll long long
#define pb(a) push_back(a)
#define mkp(a, b) make_pair(a, b)
#define mst(a, c) memset(a, c, sizeof(a))
#define rep(a, b, c) for(int (a) = (b); (a) <= (c); (a)++)
#define per(a, b, c) for(int (a) = (b); (a) >= (c); (a)--)
using namespace std;
int read()
{int num = 0; bool f = 0; char ch = getchar();while(ch < '0' || ch > '9') {f = (ch == '-'); ch = getchar();}while(ch >= '0' && ch <= '9') {num = (num << 1) + (num << 3) + ch - '0'; ch = getchar();}return f? -num : num;
}
//void add_edge(int x, int y, int c)
//{//  edg[++cnt].to = y; edg[cnt].val = c; edg[cnt].nxt = hed[x]; hed[x] = cnt;
//  edg[++cnt].to = x; edg[cnt].val = c; edg[cnt].nxt = hed[y]; hed[y] = cnt;
//}
int work()
{}
int main()
{//  clock_t TAT = clock();
//=====================================per(_, re, 1) {work();}
//=====================================
//  cout<<"Time::"<<clock() - TAT<<"ms"<<'\n';return 0;
}

高精度

struct INTEGER
{vector <int> vec;static const int B = 1e4;INTEGER(ll x = 0){while(x) vec.pb(x % B), x /= B;if(!vec.size()) vec.pb(0);}void init(int len = 1) {vec.clear(); vec.resize(len, 0);}void top0() {while(vec.size() > 1 && !vec.back()) vec.pop_back();}INTEGER operator + (const INTEGER &a) const{int len = max(vec.size(), a.vec.size());INTEGER tmp; tmp.init(len + 1); rep(i, 0, len - 1){if(i < vec.size()) tmp.vec[i] += vec[i];if(i < a.vec.size()) tmp.vec[i] += a.vec[i];if(tmp.vec[i] >= B) tmp.vec[i + 1]++, tmp.vec[i] -= B;}tmp.top0(); return tmp;}INTEGER operator * (const INTEGER &a) const{INTEGER tmp; tmp.init(a.vec.size() + vec.size() + 5);int n = vec.size(), m = a.vec.size();rep(i, 0, n - 1)rep(j, 0, m - 1){tmp.vec[i + j] += vec[i] * a.vec[j];if(tmp.vec[i + j] >= 2e9) tmp.vec[i + j + 1] += tmp.vec[i + j] / B, tmp.vec[i + j] %= B;}   n = tmp.vec.size() - 1;rep(i, 0, n) if(tmp.vec[i] >= B) tmp.vec[i + 1] += tmp.vec[i] / B, tmp.vec[i] %= B;tmp.top0(); return tmp;}void read(){string str; cin>>str;  int t = 0, len = str.size(), las = len, f = (len % 4 != 0); init(len / 4 + f); for(int i = max(0, len - 4); i >= 0; i -= (i >= 4)? 4 : (!i)? 1 : i) {int tmp = 0;for(int j = i; j < i + 4 && j < las; j++) tmp = tmp * 10 + str[j] - '0';vec[t++] = tmp; las = i;}top0();}void print() {printf("%d", vec[vec.size() - 1]);per(i, vec.size() - 2, 0) printf("%04d", vec[i]);}
};

Celoria的板子(last update:20201017)相关推荐

  1. 个人ACM模板(待持续补充)

    文章目录 前言 1.排序 (1) 快速排序 (2) 归并排序(求逆序对) 2.基础算法 (1) 二分 3.数学 (1) 线性筛(朴素,最小质因子,因子数,欧拉函数) - 朴素线性筛 - 最小质因子筛 ...

  2. 算法补完计划(五) 二分图匹配

    二分图 如果一张图能被分为两部分,两部分之间存在边相连,而单个部分内的结点无边相连,那这张图叫做二分图 判断二分图 我们给图进行染色,从一个点开始染成红色,相邻点染蓝色,最后能全部染完,并且任意相邻点 ...

  3. NOIP2018赛前停课集训记——最后的刷板子计划

    前言 再过两天就\(NOIP2018\)了. 于是,我决定不做其他题目,开始一心一意刷板子了. 这篇博客记录的就是我的刷板子计划. [洛谷3383][模板]线性筛素数 这种普及-的题目我还写挂了两次( ...

  4. ROC-RK3328-CC板子编译烧录环境记录

    3328的官网 http://www.t-firefly.com/doc/product/index/id/34.html 官方网站:http://www.t-firefly.com 开发者社区:ht ...

  5. Altium Designer画板子步骤

    Altium Designer画板子步骤 1.新建PCB工程 2.新建原理图库,绘制原理图封装 3.新建PCB库,绘制元件PCB封装,可以从立创商城下载 4.关联元件的原理图和PCB封装 5.新建原理 ...

  6. 虚拟机使用adb连接板子

    虚拟机使用adb连接板子 1.首先要让虚拟机能识别到板子,才能使用adb 连接到板子,首先要打开这个按钮,如果没有这这个按钮需要执行第二步操作,如果有就不需要执行第二步 2.将虚拟机关机后,把下图中的 ...

  7. tx2板子安torch、opencv以及安装环境技巧

    tx2板子系统为Arm64,与普通的x86系统安装环境时使用的安装包或者是源代码不同,有些软件一般用apy-get以及pip是安装不上的.本文讲述整个TX2板子刷机到安装torch.opencv.te ...

  8. Altium Designer绘制PCB板子的基本步骤

    Altium Designer绘制PCB板子的基本步骤 前言 一. 建立元器件库 二. 建立工程,建立原理图,建立PCB 三. 画原理图 四. 画pcb图 五.其他有关知识讲解 六.其他学习资料连接 ...

  9. 面向考研的数据结构板子

    数据结构板子 考研复习对着书看了一遍数据结构之后总觉得缺了点什么,正好以前打比赛的板子也找不到了,就在这写一点数据结构的基础板子找找手感,举的例子也都是一些简单题,希望能对复习有所帮助.我在写板子的时 ...

最新文章

  1. 一个 .git 目录,领悟 Git 的强大!
  2. 简单选择排序--转载
  3. 等保2.0标准_信息安全技术标准与等保2.0
  4. python时间处理模块有哪些_Python模块之时间处理
  5. 那个成人总会遇到的小问题……
  6. [vue] 如何解决vue打包vendor过大的问题?
  7. 如何使用ES6中的参数
  8. android 工厂模式创建,7、Android设计模式---(创建型设计模式)抽象工厂模式
  9. 【java】LongAdder源码分析原理分析
  10. Dom-Attribute对象
  11. 使用ffmpeg一行命令根据时间分割MP4文件
  12. python 修改图片_Python实现批量修改图片格式和大小的方法【opencv库与PIL库】
  13. oracle bitmap btree 索引,oracle之bitmap索引
  14. 测绘类(遥感)投稿期刊(卓越期刊、EI、CSCD、核心期刊)汇总,内附投稿链接
  15. 程序员为什么要转行项目经理
  16. Linux 搭建NodeBB社区,搭建CAS登录认证平台,实现Nodebb接入企业CAS认证(二)
  17. 设置计算机ip地址时网关的作用是什么,IP地址小课堂:起到门户作用的网关到底有多重要?...
  18. discard是什么意思啊(discard是什么意思翻译)
  19. *基于RT-Thread的战舰开发板连接Onenent云平台(学习笔记)**
  20. 找出数组中第k大和第m大的数字之和

热门文章

  1. Python网络爬虫:基础知识Beautiful Soup
  2. wpf DataGrid主从表,DataGrid嵌套DataGrid主从结构rowdetailtemplate实现,绑定DataTable数据源,使用Visual Studio 2017
  3. Android原生OS风格ROM包,ZUK Z1 魔趣OS 安卓9 MagiskV21版 完美ROOT 纯净完美 原生极简 纯净推荐...
  4. Jenkins+Gitlab+Nginx+Maven编译Java项目自动发布与基于tag版本回退(重复构建问题已解决)
  5. JasperReport类进行PDF打印导致内容缺失
  6. 有哪些道理你后悔没有早点知道?
  7. USB2.0实际传输速度为什么与480mbps相差甚远
  8. 疯狂Java讲义(七)----第二部分
  9. 华为鸿蒙无人驾驶,特斯拉最大的对手竟是华为?Hicar+鸿蒙OS无人驾驶技术不再一家独大!...
  10. java基础 - 网上书城