前言
因为loceaner太菜了,他什么东西都不会
所以他打算学一个东西就记录一下
不过因为他很菜,所以他不会写原理……
而且,他希望在2019CSP之前不会断更
就酱紫,就是写给他自己的……因为他太菜了
基础算法
小技巧
\[\sum_{i = 0}^{x}C(x, i)* C(y, i) = C(x + y, x) \]
使用负数下标
如何使用负数下标呢?
让数组前面有东西
int y[100];
int *z = y + 50;
这样的话调用\(z[-50]\)就变成了调用\(y[0]\)
z[-50] = y[0];
然后这样就可以实现调用啦~
其实还有一个更暴力的方法:用\(map\)
\(map\)是\(\log n\)的\(map\)\(unordered\_map\)是\(O(1)\)的\(map\)(到\(c++11\)才会有)
二维前缀和
//知识点:二维前缀和
/*
By:Loceaner
*/
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
return x * f;
}
const int N = 1000;
int n, m;
int a[N][N], b[N][N];
int main() {
n = read(), m = read();
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
a[i][j] = read();
b[i][j] = a[i][j] + b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1];
}
}
for(int i, u1, v1, u2, v2; i <= m; i++) {
u1 = read(), v1 = read(), u2 = read(), v2 = read();
cout << b[u2][v2] - b[u1 - 1][v2] - b[u2][v1 - 1] + b[u1 - 1][v1 - 1] << '\n';
}
return 0;
}
三分法
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int A = 1e5 + 11;
const int B = 1e6 + 11;
const double eps = 1e-6;
inline int read() {
char c = getchar(); int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int n;
double l, r, a[A];
double f(double x) {
double ans = 0;
for(int i = 1; i <= n + 1; i++) ans = ans * x + a[i];
return ans;
}
int main() {
n = read(); scanf("%lf%lf", &l, &r);
for(int i = 1; i <= n + 1; i++) scanf("%lf", &a[i]);
while(r - l >= eps) {
double qwq = (r - l) / 3.0, lmid = l + qwq, rmid = r - qwq;
if(f(lmid) > f(rmid)) r = rmid;
else l = lmid;
}
printf("%.5lf", l);
return 0;
}
二维差分
//知识点:
/*
By:Loceaner
*/
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
return x * f;
}
const int N = 1e3 + 11;
int n, m, a[N][N];
int main() {
n = read(), m = read();
for(int i = 1, u1, u2, v1, v2; i <= m; i++) {
u1 = read(), v1 = read(), u2 = read(), v2 = read();
a[u1][v1] += 1;
a[u2 + 1][v2 + 1] += 1;
a[u2 + 1][v1] -= 1;
a[u1][v2 + 1] -= 1;
}
//C[x1][y1] += x , C[x2 + 1][y2 + 1] += x , C[x1][y2 + 1] -= x , C[x2 + 1][y1] -= x;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
a[i][j] = a[i][j] + a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1];;
}
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
cout << a[i][j] << ' ';
}
cout << '\n';
}
return 0;
}
归并排序
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int A = 1e5 + 11;
const int B = 1e6 + 11;
inline int read() {
char c = getchar(); int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
return x * f;
}
int n, m, a[A], b[A];
void solve(int l, int r) {
if(l == r) return;
int mid = (l + r) >> 1;
solve(l, mid), solve(mid + 1, r);
int i = l, j = mid + 1, k = l;
while(i <= mid && j <= r) {
if(a[i] <= a[j]) b[k++] = a[i++];
else b[k++] = a[j++];
}
while(i <= mid) b[k++] = a[i++];
while(j <= r) b[k++] = a[j++];
for(int i = l; i <= r; i++) a[i] = b[i];
}
int main() {
// freopen("a.in", "r", stdin);
n = read();
for(int i = 1; i <= n; i++) a[i] = read();
solve(1, n);
for(int i = 1; i <= n; i++) cout << a[i] << ' ';
return 0;
}
排序不等式
给定3组数\(a, b, c\)\(a[1]\)$a[n]$,$b[1]$\(b[n]\),\(c[1]\)~\(c[n]\)
其中\(c[1]\)$c[n]$是$b[1]$\(b[n]\)的乱序排列\(a[1]*b[n]+a[2]*b[n-1]+...<=a[1]*c[1]+a[2]*c[2]+...<=a[1]*b[1]+a[2]*b[2]+...\)
即:逆序和 <= 乱序和 <= 正序和
关于\(long\ long\)
在日常的题目中,一定要看好数据范围,如果会爆\(int\)的话,不要忘记开\(long long\)(无数次被坑!!)
高精度模板
最让人烦的就是高精度了,某些题并不难,但是要写高精。。烦\(\color{white}{(ps:板子来自lfd)}\)
namespace BigInteger {
struct Big_integer {
int d[10005], len;
void clean() {while(len > 1 and !d[len - 1]) len--;}
Big_integer() {memset(d, 0, sizeof d);len = 1;}
Big_integer(int num) {*this = num;}
Big_integer operator = (const char* num) {
memset(d, 0, sizeof d);
len = strlen(num);
for (int i = 0; i < len; i++) d[i] = num[len - 1 - i] - '0';
clean();
return *this;
}
Big_integer operator = (int num) {
char s[10005];
sprintf(s, "%d", num);
*this = s;
return *this;
}
Big_integer operator * (const Big_integer &b) const {
int i, j;
Big_integer c;
c.len = len + b.len;
for (j = 0; j < b.len; j++)
for (i = 0; i < len; i++)
c.d[i + j] += d[i] * b.d[j];
for (i = 0; i < c.len - 1; i++) c.d[i + 1] += c.d[i] / 10, c.d[i] %= 10;
c.clean();
return c;
}
Big_integer operator / (const int &b) {
int i, j, a = 0;
Big_integer c = *this;
for (i = len - 1; i >= 0; i--) {
a = a * 10 + d[i];
for (j = 0; j < 10; j++) if (a < b * (j + 1)) break;
c.d[i] = j;
a = a - b * j;
}
c.clean();
return c;
}
bool operator < (const Big_integer &b) const {
if (len != b.len) return len < b.len;
for (int i = len - 1; i >= 0; i--)
if (d[i] != b.d[i])
return d[i] < b.d[i];
return false;
}
string str() const {
char s[10005];
for (int i = 0; i < len; i++) s[len - 1 - i] = d[i] + '0';
return s;
}
};
istream& operator >> (istream& in, Big_integer &x) {
string s;
in >> s;
x = s.c_str();
return in;
}
ostream& operator << (ostream& out, const Big_integer &x) {
out << x.str();
return out;
}
}
using namespace BigInteger;
数据结构
树状数组
单点修改,区间查询
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lowbit(x) (x & (-x))
using namespace std;
const int A = 5e5 + 11;
const int B = 1e6 + 11;
inline int read() {
char c = getchar(); int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int n, m, c[B];
void update(int x, int k) {
while(x <= n) {
c[x] += k;
x += lowbit(x);
}
}
int query(int x) {
int ans = 0;
while(x) {
ans += c[x];
x -= lowbit(x);
}
return ans;
}
int main() {
n = read(), m = read();
for(int i = 1, a; i <= n; i++) {
a = read();
update(i, a);
}
while(m--) {
int opt = read(), x = read(), y = read();
if(opt == 1) update(x, y);
else cout << query(y) - query(x - 1) << '\n';
}
return 0;
}
区间修改,单点查询
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lowbit(x) (x & (-x))
using namespace std;
const int A = 5e5 + 11;
const int B = 1e6 + 11;
inline int read() {
char c = getchar(); int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int n, m, c[B], a[B];
void update(int x, int k) {
while(x <= n) {
c[x] += k;
x += lowbit(x);
}
}
int query(int x) {
int ans = 0;
while(x) {
ans += c[x];
x -= lowbit(x);
}
return ans;
}
int main() {
n = read(), m = read();
for(int i = 1; i <= n; i++) a[i] = read();
while(m--) {
int opt = read(), x = read(), y, k;
if(opt == 1) y = read(), k = read(), update(x, k), update(y + 1, -k);
else cout << a[x] + query(x) << '\n';
}
return 0;
}
线段树
区间修改,区间查询
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;
const int A = 1e5 + 11;
const int B = 1e6 + 11;
inline int read() {
char c = getchar(); int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int n, m;
namespace Seg {
#define lson rt << 1
#define rson rt << 1 | 1
struct tree {
int l, r, w, lazy;
} t[A << 2];
inline void pushup(int rt) { t[rt].w = t[lson].w + t[rson].w; }
inline void pushdown(int rt) {
t[lson].lazy += t[rt].lazy, t[rson].lazy += t[rt].lazy;
t[lson].w += (t[lson].r - t[lson].l + 1) * t[rt].lazy;
t[rson].w += (t[rson].r - t[rson].l + 1) * t[rt].lazy;
t[rt].lazy = 0;
}
void build(int rt, int l, int r) {
t[rt].l = l, t[rt].r = r;
if(l == r) { t[rt].w = read(); return; }
int mid = (l + r) >> 1;
build(lson, l, mid), build(rson, mid + 1, r);
pushup(rt); return;
}
void update(int rt, int l, int r, int val) {
if(l <= t[rt].l && t[rt].r <= r) {
t[rt].lazy += val;
t[rt].w += (t[rt].r - t[rt].l + 1) * val;
return;
}
if(t[rt].lazy) pushdown(rt);
int mid = (t[rt].l + t[rt].r) >> 1;
if(l <= mid) update(lson, l, r, val);
if(r > mid) update(rson, l, r, val);
pushup(rt); return;
}
int query(int rt, int l, int r) {
if(l <= t[rt].l && t[rt].r <= r) { return t[rt].w; }
if(t[rt].lazy) pushdown(rt);
int mid = (t[rt].l + t[rt].r) >> 1, ans = 0;
if(l <= mid) ans += query(lson, l, r);
if(r > mid) ans += query(rson, l, r);
return ans;
}
}
signed main() {
n = read(), m = read();
Seg::build(1, 1, n);
while(m--) {
int opt = read(), x = read(), y = read(), k;
if(opt == 1) k = read(), Seg::update(1, x, y, k);
else cout << Seg::query(1, x, y) << '\n';
}
return 0;
}
区间加,区间乘,区间求和
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;
const int A = 1e5 + 11;
const int B = 1e6 + 11;
inline int read() {
char c = getchar(); int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int n, m, mod;
namespace Seg {
#define lson rt << 1
#define rson rt << 1 | 1
struct tre {
int l, r, w, lazy1, lazy2;
} t[A << 2];
inline void pushup(int rt) {
t[rt].w = (t[lson].w + t[rson].w) % mod;
}
inline void tag1(int rt, int val) {
t[rt].lazy1 *= val, t[rt].lazy2 *= val;
t[rt].lazy1 %= mod, t[rt].lazy2 %= mod;
t[rt].w *= val, t[rt].w %= mod;
}
inline void tag2(int rt, int val) {
t[rt].lazy2 += val; t[rt].lazy2 %= mod;
t[rt].w += (t[rt].r - t[rt].l + 1) * val, t[rt].w %= mod;
}
inline void pushdown(int rt) {
if(t[rt].lazy1 != 1) {
tag1(lson, t[rt].lazy1);
tag1(rson, t[rt].lazy1);
t[rt].lazy1 = 1;
}
if(t[rt].lazy2) {
tag2(lson, t[rt].lazy2);
tag2(rson, t[rt].lazy2);
t[rt].lazy2 = 0;
}
}
inline void build(int rt, int l, int r) {
t[rt].l = l, t[rt].r = r, t[rt].lazy1 = 1, t[rt].lazy2 = 0;
if(l == r) { t[rt].w = read(); return; }
int mid = (l + r) >> 1;
build(lson, l, mid), build(rson, mid + 1, r);
pushup(rt); return;
}
inline void mul(int rt, int l, int r, int val) {
if(l <= t[rt].l && t[rt].r <= r) return tag1(rt, val);
pushdown(rt);
int mid = (t[rt].l + t[rt].r) >> 1;
if(l <= mid) mul(lson, l, r, val);
if(r > mid) mul(rson, l, r, val);
pushup(rt); return;
}
inline void update(int rt, int l, int r, int val) {
if(l <= t[rt].l && t[rt].r <= r) return tag2(rt, val);
pushdown(rt);
int mid = (t[rt].l + t[rt].r) >> 1;
if(l <= mid) update(lson, l, r, val);
if(r > mid) update(rson, l, r, val);
pushup(rt); return;
}
inline int query(int rt, int l, int r) {
if(l <= t[rt].l && t[rt].r <= r) { return t[rt].w % mod; }
pushdown(rt);
int mid = (t[rt].l + t[rt].r) >> 1, ans = 0;
if(l <= mid) ans += query(lson, l, r), ans %= mod;
if(r > mid) ans += query(rson, l, r), ans %= mod;
return ans % mod;
}
}
signed main() {
n = read(), m = read(), mod = read();
Seg::build(1, 1, n);
while(m--) {
int opt = read(), x = read(), y = read(), k;
if(opt == 1) k = read() % mod, Seg::mul(1, x, y, k);
else if(opt == 2) k = read() % mod, Seg::update(1, x, y, k);
else cout << Seg::query(1, x, y) % mod << '\n';
}
return 0;
}
单调栈
for(int i = 0; i < T.size(); i++){
while(! stk.empty() && stk.top() > T[i]){
?stk.pop();
}
stk.push(A[i]);
}
单调队列
上经典的滑动窗口问题
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#define maxn 1000100
using namespace std;
int q[maxn], a[maxn];
int n, k;
void getmin() {
int head = 0, tail = 0;
for (int i = 1; i < k; i++) {
while (head <= tail && a[q[tail]] >= a[i]) tail--;
q[++tail] = i;
}
for (int i = k; i <= n; i++) {
while (head <= tail && a[q[tail]] >= a[i]) tail--;
q[++tail] = i;
while (q[head] <= i - k) head++;
printf("%d ", a[q[head]]);
}
}
void getmax() {
int head = 0, tail = 0;
for (int i = 1; i < k; i++) {
while (head <= tail && a[q[tail]] <= a[i]) tail--;
q[++tail] = i;
}
for (int i = k; i <= n; i++) {
while (head <= tail && a[q[tail]] <= a[i]) tail--;
q[++tail] = i;
while (q[head] <= i - k) head++;
printf("%d ", a[q[head]]);
}
}
int main() {
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
getmin();
printf("\n");
getmax();
printf("\n");
return 0;
}
树剖
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int A = 1e6 + 11;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
return x * f;
}
int n, m, root, mod, w[A], pre[A];
struct node {
int to, nxt;
} e[A];
int head[A], cnt;
inline void add_edge(int from, int to) {
e[++cnt].to = to;
e[cnt].nxt = head[from];
head[from] = cnt;
}
namespace Seg {
struct tree {
int l, r, w, lazy;
} t[A];
#define lson rt << 1
#define rson rt << 1 | 1
inline void pushup(int rt) {
t[rt].w = (t[lson].w + t[rson].w) % mod;
}
inline void pushdown(int rt) {
t[lson].lazy += t[rt].lazy, t[rson].lazy += t[rt].lazy;
t[lson].lazy %= mod, t[rson].lazy %= mod;
t[lson].w += (t[lson].r - t[lson].l + 1) * t[rt].lazy; t[lson].w %= mod;
t[rson].w += (t[rson].r - t[rson].l + 1) * t[rt].lazy; t[lson].w %= mod;
t[rt].lazy = 0;
}
void build(int rt, int l, int r) {
t[rt].l = l, t[rt].r = r;
if(l == r) { t[rt].w = w[pre[l]] % mod; return; }
int mid = (l + r) >> 1;
build(lson, l, mid); build(rson, mid + 1, r);
pushup(rt); return;
}
void add(int rt, int l, int r, int val) {
if(l <= t[rt].l && t[rt].r <= r) {
t[rt].lazy = (t[rt].lazy + val) % mod;
t[rt].w = (t[rt].w + (t[rt].r - t[rt].l + 1) * val) % mod;
return;
}
if(t[rt].lazy) pushdown(rt);
int mid = (t[rt].l + t[rt].r) >> 1;
if(l <= mid) add(lson, l, r, val);
if(r > mid) add(rson, l, r, val);
pushup(rt);
}
int asksum(int rt, int l, int r) {
if(l <= t[rt].l && t[rt].r <= r) {
return t[rt].w % mod;
}
if(t[rt].lazy) pushdown(rt);
int mid = (t[rt].l + t[rt].r) >> 1, ans = 0;
if(l <= mid) ans += asksum(lson, l, r);
if(r > mid) ans += asksum(rson, l, r);
return ans;
}
}
int dfn[A], son[A], siz[A], dep[A], fa[A], top[A], tot;
void dfs1(int now, int fr) {
siz[now] = 1, fa[now] = fr, dep[now] = dep[fr] + 1;
for(int i = head[now]; i; i = e[i].nxt) {
int to = e[i].to;
if(to == fr) continue;
dfs1(to, now);
siz[now] += siz[to];
if(siz[to] > siz[son[now]]) son[now] = to;
}
}
void dfs2(int now, int tp) {
dfn[now] = ++tot, pre[tot] = now, top[now] = tp;
if(son[now]) dfs2(son[now], tp);
for(int i = head[now]; i; i = e[i].nxt) {
int to = e[i].to;
if(to == fa[now] || to == son[now]) continue;
dfs2(to, to);
}
}
inline void add_qwq(int x, int y, int val) {
while(top[x] != top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
Seg::add(1, dfn[top[x]], dfn[x], val);
x = fa[top[x]];
}
if(dep[x] > dep[y]) swap(x, y);
Seg::add(1, dfn[x], dfn[y], val);
return;
}
inline int asksum_qwq(int x, int y) {
int ans = 0;
while(top[x] != top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
ans += Seg::asksum(1, dfn[top[x]], dfn[x]);
ans %= mod;
x = fa[top[x]];
}
if(dep[x] > dep[y]) swap(x, y);
ans += Seg::asksum(1, dfn[x], dfn[y]);
ans %= mod;
return ans % mod;
}
int main() {
n = read(), m = read(), root = read(), mod = read();
for(int i = 1; i <= n; i++) w[i] = read() % mod;
for(int i = 1; i < n; i++) {
int x = read(), y = read();
add_edge(x, y), add_edge(y, x);
}
dfs1(root, 0);
dfs2(root, root);
Seg::build(1, 1, n);
while(m--) {
int opt = read(), x, y, z;
if(opt == 1) x = read(), y = read(), z = read() % mod, add_qwq(x, y, z);
if(opt == 2) x = read(), y = read(), cout << asksum_qwq(x, y) % mod << '\n';
if(opt == 3) x = read(), z = read(), Seg::add(1, dfn[x], dfn[x] + siz[x] - 1, z);
if(opt == 4) x = read(), cout << Seg::asksum(1, dfn[x], dfn[x] + siz[x] - 1) % mod << '\n';
}
return 0;
}
求LCA
树剖求LCA
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int A = 5e5 + 11;
const int B = 1e6 + 11;
inline int read() {
char c = getchar(); int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int n, m, R;
struct node { int to, nxt; } e[A << 1];
int head[A], cnt, dep[A], son[A], dfn[A], siz[A], fa[A], top[A], tot;
inline void add(int from, int to) {
e[++cnt].to = to;
e[cnt].nxt = head[from];
head[from] = cnt;
}
void prepare(int now, int fr) {
fa[now] = fr, dep[now] = dep[fr] + 1, siz[now] = 1;
for(int i = head[now]; i; i = e[i].nxt) {
int to = e[i].to;
if(to == fr) continue;
prepare(to, now); siz[now] += siz[to];
if(siz[to] > siz[son[now]]) son[now] = to;
}
}
void dfs(int now, int tp) {
top[now] = tp, dfn[now] = ++tot;
if(son[now]) dfs(son[now], tp);
for(int i = head[now]; i; i = e[i].nxt) {
int to = e[i].to;
if(to == fa[now] || to == son[now]) continue;
dfs(to, to);
}
}
inline int LCA(int x, int y) {
while(top[x] != top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
x = fa[top[x]];
}
if(dep[x] > dep[y]) swap(x, y);
return x;
}
int main() {
n = read(), m = read(), R = read();
for(int i = 1, x, y; i < n; i++) {
x = read(), y = read();
add(x, y), add(y, x);
}
prepare(R, 0); dfs(R, R);
while(m--) {
int x = read(), y = read();
cout << LCA(x, y) << '\n';
}
return 0;
}
倍增求LCA
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int A = 5e5 + 11;
const int B = 1e6 + 11;
inline int read() {
char c = getchar(); int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int n, m, R;
struct node { int to, nxt; } e[A << 1];
int head[A], cnt, dep[A], fa[A][23], lg[A];
inline void add(int from, int to) {
e[++cnt].to = to;
e[cnt].nxt = head[from];
head[from] = cnt;
}
void dfs(int now, int fr) {
fa[now][0] = fr, dep[now] = dep[fr] + 1;
for(int i = head[now]; i; i = e[i].nxt) {
int to = e[i].to;
if(to == fr) continue;
dfs(to, now);
}
}
inline int LCA(int x, int y) {
if(dep[x] < dep[y]) swap(x, y);
for(int i = 20; i >= 0; i--) if(dep[fa[x][i]] >= dep[y]) x = fa[x][i];
if(x == y) return x;
for(int i = 20; i >= 0; i--) if(fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
return fa[x][0];
}
int main() {
n = read(), m = read(), R = read(); lg[1] = 0;
for(int i = 2, x, y; i <= n; i++) {
x = read(), y = read();
add(x, y), add(y, x);
lg[i] = lg[i >> 1] + 1;
}
dfs(R, 0);
for(int j = 1; (1 << j) <= n; j++)
for(int i = 1; i <= n; i++)
fa[i][j] = fa[fa[i][j - 1]][j - 1];
while(m--) {
int x = read(), y = read();
cout << LCA(x, y) << '\n';
}
return 0;
}
ST表
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int A = 1e5 + 11;
const int B = 1e6 + 11;
inline int read() {
char c = getchar(); int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int n, m, a[B], f[B][25], lg[B];
inline int query(int l, int r) {
int k = lg[r - l + 1];
return max(f[l][k], f[r - (1 << k) + 1][k]);
}
int main() {
n = read(), m = read(); lg[0] = -1;
for(int i = 1; i <= n; i++) a[i] = read(), f[i][0] = a[i], lg[i] = lg[i >> 1] + 1;
for(int j = 1; (1 << j) <= n; j++)
for(int i = 1; i <= n; i++)
f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
while(m--) {
int x = read(), y = read();
cout << query(x, y) << '\n';
}
return 0;
}
数学/数论
求逆元
递推1~n的逆元
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
const int A = 1e5 + 11;
const int B = 3e6 + 11;
inline int read() {
char c = getchar(); int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int n, p;
ll inv[B];
int main() {
n = read(), p = read();
inv[1] = 1;
for(int i = 2; i <= n; i++) {
inv[i] = 1LL * (p - p / i) * inv[p % i] % p;
}
for(int i = 1; i <= n; i++) cout << inv[i] << '\n';
return 0;
}
矩阵快速幂
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;
const int A = 1e2 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
inline int read() {
char c = getchar(); int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = + (c ^ 48);
return x * f;
}
int n, k;
struct matrix {
int a[A][A];
matrix() { memset(a, 0, sizeof(a)); }
void init() { for(int i = 1; i <= n; i++) a[i][i] = 1; }
} ans, a;
matrix operator * (const matrix &x, const matrix &y) {
matrix qwq;
for(int k = 1; k <= n; k++)
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
qwq.a[i][j] = (qwq.a[i][j] + x.a[i][k] * y.a[k][j] % mod) % mod;
return qwq;
}
inline void power() {
while(k) {
if(k & 1) ans = ans * a;
a = a * a; k >>= 1;
}
}
signed main() {
n = read(), k = read();
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
a.a[i][j] = read();
ans.init();
power();
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
cout << ans.a[i][j] << " ";
}
puts("");
}
return 0;
}
快速乘
//知识点:快速乘
/*
By:Loceaner
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#define int long long
using namespace std;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
return x * f;
}
int a, b, p, ans;
int mul(int a, int b, int mod) {
int res = 0;
while(b) {
if(b & 1) res = (res + a) % mod;
a = (a + a) % mod;
b >>= 1;
}
return res % mod;
}
signed main() {
a = read(), b = read(), p = read();
ans = mul(a, b, p);
cout << ans << '\n';
return 0;
}
快速幂
//知识点:快速幂
/*
By:Loceaner
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#define int long long
using namespace std;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
return x * f;
}
int a, b, p, ans;
int power(int a, int b, int mod) {
int res = 1;
while(b) {
if(b & 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res % mod;
}
signed main() {
a = read(), b = read(), p = read();
ans = power(a, b, p);
cout << ans << '\n';
return 0;
}
埃氏筛
void prime(int n) {
cnt = 0;
vis[0] = vis[1] = 1;
for(int i = 2; i <= n; ++i) {
if(!vis[i]) {
p[++cnt] = i;
for(int j = i * i; j <= n; j+=i) {
vis[j] = true;
}
}
}
}
线性筛
int vis[N], p[N], cnt;
void prepare() {
vis[0] = vis[1] = 1;
for(int i = 2; i <= n; i++) {
if(!vis[i]) p[++cnt] = i;
for(int j = 1; j <= cnt; j++) {
if(i * p[j] > n) break;
vis[i * p[j]] = 1;
if(i % p[j] == 0) break;
}
}
}
动态规划
最长上升子序列
普通二分
//知识点:
/*
By:Loceaner
*/
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
return x * f;
}
const int N = 10001;
int f[N], a[N], n;
int len = 1;
int main() {
memset(f, 0x3f, sizeof(f));
n = read();
for(int i = 1; i <= n; i++) a[i] = read();
f[len] = a[1];
for(int i = 2; i <= n; i++) {
int l = 1, r = len, mid, rec;
if(a[i] > f[len]) f[++len] = a[i];
else {
while(l <= r) {
mid = (l + r) / 2;
if(f[mid] >= a[i]) rec = mid, r = mid - 1;
else l = mid + 1;
}
f[rec] = min(f[rec], a[i]);
}
}
for(int i = 1; i <= len; i++) cout << f[i] << " ";
cout << '\n' << len << '\n';
return 0;
}
/*
9
7 2 1 5 6 4 3 8 9
*/
lower_bound
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
return x * f;
}
const int N = 10001;
int f[N], a[N], n;
int len = 1;
int main() {
memset(f, 0x3f, sizeof(f));
n = read();
for(int i = 1; i <= n; i++) a[i] = read();
f[1] = a[1];
for(int i = 2; i <= n; i++) {
if(a[i] > f[len]) f[++len] = a[i];
else {
int p = lower_bound(f + 1, f + len + 1 , a[i]) - f;
f[p] = a[i];
}
}
for(int i = 1; i <= len; i++) cout << f[i] << " ";
cout << '\n' << len << '\n';
return 0;
}
最长公共子序列
\(n^2\)
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
return x * f;
}
const int N = 1011;
int dp[N][N], a1[N], a2[N], n, m;
int main() {
n = read();
for(int i = 1; i <= n; i++) a1[i] = read();
for(int i = 1; i <= n; i++) a2[i] = read();
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++) {
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
if(a1[i] == a2[j]) dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + 1);
}
cout << dp[n][n] << '\n';
return 0;
}
图论
tarjan
#include <bits/stdc++.h>
using namespace std;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = x * 10 + c - 48;
return x * f;
}
const int N = 1011;
struct node {
int to, nxt;
} e[N];
int low[N], dfn[N], tot, topp = 0, sta[N], cnt, head[N];
bool vis[N];
inline void add(int from, int to) {
e[++tot].to = to;
e[tot].nxt = head[from];
head[from] = tot;
}
void tarjan(int u) {
dfn[u] = low[u] = ++cnt, sta[++topp] = u, vis[u] = 1;
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if(!dfn[v]) tarjan(v), low[u] = min(low[u], low[v]);
else if(vis[v]) low[u] = min(low[u], dfn[v]);
}
if(dfn[u] == low[u]) {
do {
cout << sta[topp] << ' ';
vis[sta[topp--]] = 0;
}while(u != sta[topp + 1]);
cout << '\n';
}
}
int n, m;
int main() {
n = read(), m = read();
for(int i = 1; i <= m; i++) {
int u = read(), v = read();
add(u, v);
}
for(int i = 1; i <= n; i++)
if(!dfn[i]) tarjan(i);
}
/*
5 8
1 2
2 3
3 6
5 6
1 4
4 5
5 1
2 5
*/
最小生成树
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int A = 2e5 + 11;
const int B = 1e6 + 11;
inline int read() {
char c = getchar(); int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
return x * f;
}
int n, m, fa[A], cnt, ans;
struct node { int x, y, val; } e[A];
int find(int x){ return fa[x] == x ? x : fa[x] = find(fa[x]); }
bool cmp(node x, node y) { return x.val < y.val; }
int main() {
n = read(), m = read();
for(int i = 1; i <= n; i++) fa[i] = i;
for(int i = 1; i <= m; i++) e[i].x = read(), e[i].y = read(), e[i].val = read();
sort(e + 1, e + 1 + m, cmp);
for(int i = 1; i <= m; i++) {
int dx = find(e[i].x), dy = find(e[i].y);
if(dx != dy) {
fa[dy] = dx;
ans += e[i].val;
cnt++;
if(cnt == n - 1) break;
}
}
cout << ans << '\n';
return 0;
}
求树的直径
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
return x * f;
}
const int M = 3e5 + 11;
int n, cnt, k, ans, head[M], dep[M], vis[M];
struct node {
int nxt, to;
} edge[M];
void add(int from, int to) {
edge[++cnt].nxt = head[from];
edge[cnt].to = to;
head[from] = cnt;
}
void dfs(int x, int fx) {
vis[x] = 1;
for(int i = head[x]; i; i = edge[i].nxt) {
int to = edge[i].to;
if(to == fx) continue;
dep[to] = dep[x] + 1;
if(ans < dep[to]) {
ans = dep[to];
k = to;
}
dfs(to, x);
}
}
int main() {
n = read();
for(int i = 1; i < n; i++) {
int x = read(), y = read();
add(x, y), add(y, x);
ans = 0, dep[x] = 0, memset(vis, 0, sizeof(vis)); dfs(x, 0);
ans = 0, dep[k] = 0, memset(vis, 0, sizeof(vis)); dfs(k, 0);
cout << ans << '\n';
}
return 0;
}
二分图匹配
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int A = 1e6 + 11;
const int B = 1e6 + 11;
inline int read() {
char c = getchar(); int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int n, m, E, ans;
struct node { int to, nxt; } e[A];
int head[A], cnt, match[A], vis[A];
inline void add(int from, int to) {
e[++cnt].to = to;
e[cnt].nxt = head[from];
head[from] = cnt;
}
bool dfs(int now) {
for(int i = head[now]; i; i = e[i].nxt) {
int to = e[i].to;
if(vis[to]) continue;
vis[to] = 1;
if(!match[to] || dfs(match[to])) {
match[to] = now;
return 1;
}
}
return 0;
}
int main() {
n = read(), m = read(), E = read();
for(int i = 1, x, y; i <= E; i++) {
x = read(), y = read();
if(x > n || y > m) continue;
add(x, y);
}
for(int i = 1; i <= n; i++) {
memset(vis, 0, sizeof(vis));
if(dfs(i)) ans++;
}
cout << ans << '\n';
return 0;
}
最短路
堆优化dij
#include <queue>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int A = 1e5 + 11;
const int B = 1e6 + 11;
const int inf = 0x3f3f3f3f;
inline int read() {
char c = getchar(); int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int n, m, dis[A], S;
struct node { int to, nxt, val; } e[B];
int head[A], cnt;
inline void add(int from, int to, int val) {
e[++cnt].to = to;
e[cnt].val = val;
e[cnt].nxt = head[from];
head[from] = cnt;
}
struct edge {
int x, y;
bool operator < (const edge &qwq) const {
return y > qwq.y;
}
};
priority_queue<edge> Q;
inline void ZDL() {
memset(dis, inf, sizeof(dis));
dis[S] = 0;
Q.push((edge) {S, 0});
while(!Q.empty()) {
int u = Q.top().x, d = Q.top().y; Q.pop();
if(d != dis[u]) continue;
for(int i = head[u]; i; i = e[i].nxt) {
int to = e[i].to;
if(dis[to] > dis[u] + e[i].val) {
dis[to] = dis[u] + e[i].val;
Q.push((edge) {to, dis[to]});
}
}
}
}
int main() {
// freopen("testdata.in", "r", stdin);
n = read(), m = read(), S = read();
for(int i = 1, x, y, val; i <= m; i++) {
x = read(), y = read(), val = read();
add(x, y, val);
}
ZDL();
for(int i = 1; i <= n; i++) {
if(dis[i] == inf) cout << "2147483647 ";
else cout << dis[i] << " ";
}
return 0;
}
SPFA
#include <queue>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int A = 1e5 + 11;
const int B = 1e6 + 11;
const int inf = 0x3f3f3f3f;
inline int read() {
char c = getchar(); int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int n, m, dis[A], S, vis[A];
struct node { int to, nxt, val; } e[B];
int head[A], cnt;
inline void add(int from, int to, int val) {
e[++cnt].to = to;
e[cnt].val = val;
e[cnt].nxt = head[from];
head[from] = cnt;
}
queue <int> Q;
inline void SPFA() {
memset(dis, inf, sizeof(dis));
dis[S] = 0, vis[S] = 1;
Q.push(S);
while(!Q.empty()) {
int u = Q.front(); Q.pop(); vis[u] = 0;
for(int i = head[u]; i; i = e[i].nxt) {
int to = e[i].to;
if(dis[to] > dis[u] + e[i].val) {
dis[to] = dis[u] + e[i].val;
if(!vis[to]) {
vis[to] = 1;
Q.push(to);
}
}
}
}
}
signed main() {
n = read(), m = read(), S = read();
for(int i = 1, x, y, val; i <= m; i++) {
x = read(), y = read(), val = read();
add(x, y, val);
}
SPFA();
for(int i = 1; i <= n; i++) cout << dis[i] << " ";
return 0;
}
判负环
#include <queue>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int A = 1e5 + 11;
const int B = 1e6 + 11;
const int inf = 0x3f3f3f3f;
inline int read() {
char c = getchar(); int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int n, m, dis[A], S = 1, vis[A], tot[A];
struct node { int to, nxt, val; } e[B];
int head[A], cnt;
inline void add(int from, int to, int val) {
e[++cnt].to = to;
e[cnt].val = val;
e[cnt].nxt = head[from];
head[from] = cnt;
}
inline bool SPFA() {
memset(dis, inf, sizeof(dis));
dis[S] = 0, vis[S] = 1, tot[S] = 1;
queue <int> Q;
Q.push(S);
while(!Q.empty()) {
int u = Q.front(); Q.pop(); vis[u] = 0;
for(int i = head[u]; i; i = e[i].nxt) {
int to = e[i].to;
if(dis[to] > dis[u] + e[i].val) {
if(++tot[to] >= n) return 1;
dis[to] = dis[u] + e[i].val;
if(!vis[to]) {
vis[to] = 1;
Q.push(to);
}
}
}
}
return 0;
}
signed main() {
int T = read();
while(T--) {
memset(head, 0, sizeof(head));
memset(vis, 0, sizeof(vis));
memset(tot, 0, sizeof(tot));
n = read(), m = read();
for(int i = 1, x, y, val; i <= m; i++) {
x = read(), y = read(), val = read();
add(x, y, val);
if(val >= 0) add(y, x, val);
}
if(SPFA()) puts("YE5");
else puts("N0");
}
return 0;
}
字符串
\(hash\)
/*
By:Loceaner
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#define ull unsigned long long
using namespace std;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
return x * f;
}
const int N = 211;
char pa[N][N], meng[N];
int n, m, a[N], l[N], ans, cnt[N];
ull p[N], cnm[N][N], sjp[N];
bool query(int l1, int r1,int now) {
ull h1, h2;
h1 = sjp[r1] - sjp[l1 - 1] * p[r1 - l1 + 1];
h2 = cnm[now][l[now]];
return h1 == h2;
}
void work2() {//cnm
memset(sjp, 0, sizeof(sjp));
int len = strlen(meng + 1);
for(int i = 1; i <= len; i++) {
sjp[i] = sjp[i - 1] * 27 + meng[i] - 'a' + 1;
}
for(int i = 1; i <= m; i++) {
for(int j = 1; j <= len; j++) {
if(meng[j] == pa[i][1]) {
if(query(j, j + l[i] - 1, i)) ans += j * a[i];
}
}
}
}
int main() {
freopen("dream.in", "r", stdin);
freopen("dream.out", "w", stdout);
n = read(), m = read();
p[0] = 1;
for(int i = 1; i <= 200; i++) p[i] = p[i - 1] * 27ull;
for(int i = 1; i <= m; i++) scanf("%s", pa[i] + 1), l[i] = strlen(pa[i] + 1);
for(int i = 1; i <= m; i++)
for(int j = 1; j <= l[i]; j++)
cnm[i][j] = cnm[i][j - 1] * 27 + pa[i][j] - 'a' + 1;
for(int i = 1; i <= m; i++) a[i] = read();
for(int i = 1; i <= n; i++) scanf("%s", meng + 1), work2();
cout << ans << '\n';
return 0;
}
KMP
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int A = 1e6 + 11;
const int B = 1e6 + 11;
inline int read() {
char c = getchar(); int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int n, m, nxt[A];
char s[A], t[A];
void get_nxt() {
int p = 0;
for(int i = 2; i <= m; i++) {
while(p && t[i] != t[p + 1]) p = nxt[p];
if(t[i] == t[p + 1]) ++p;
nxt[i] = p;
}
}
int main() {
scanf("%s", s + 1); scanf("%s", t + 1);
n = strlen(s + 1), m = strlen(t + 1);
get_nxt();
int p = 0;
for(int i = 1; i <= n; i++) {
while(p && s[i] != t[p + 1]) p = nxt[p];
if(s[i] == t[p + 1]) {
++p;
if(p == m) {
cout << i - m + 1 << '\n';
p = nxt[p];
}
}
}
for(int i = 1; i <= m; i++) cout << nxt[i] << " ";
return 0;
}