AC 자동화
코드 보기
void build_automaton() {
queue<int> q;
for (int i = 0; i < 26; ++i) {
if (trie[0][i]) q.push(trie[0][i]);
}
while (!q.empty()) {
int node = q.front(); q.pop();
for (int i = 0; i < 26; ++i) {
if (trie[node][i]) {
fail[trie[node][i]] = trie[fail[node]][i];
q.push(trie[node][i]);
} else {
trie[node][i] = trie[fail[node]][i];
}
}
}
}
사전순 배열 (SA)
코드 보기
const int MAXN = 1e6 + 5;
int n, m;
string text;
int sa[MAXN], rk[MAXN], temp_rk[MAXN], temp_sa[MAXN];
void radix_sort() {
vector<int> cnt(m + 1, 0);
for (int i = 1; i <= n; ++i) ++cnt[rk[i]];
for (int i = 1; i <= m; ++i) cnt[i] += cnt[i - 1];
for (int i = n; i >= 1; --i) sa[--cnt[rk[temp_sa[i]]]] = temp_sa[i];
}
void suffix_array() {
m = 130;
for (int i = 1; i <= n; ++i) rk[i] = text[i];
for (int i = 1; i <= n; ++i) temp_sa[i] = i;
radix_sort();
for (int w = 1, p = 0; w <= n; m = p, p = 0, w *= 2) {
for (int i = n - w + 1; i <= n; ++i) temp_sa[++p] = i;
for (int i = 1; i <= n; ++i) if (sa[i] > w) temp_sa[++p] = sa[i] - w;
radix_sort();
swap(rk, temp_sa);
p = rk[sa[1]] = 1;
for (int i = 2; i <= n; ++i) {
int a = temp_sa[sa[i]], b = temp_sa[sa[i - 1]];
int c = (i + w <= n ? temp_sa[sa[i] + w] : 0);
int d = (i - 1 + w <= n ? temp_sa[sa[i - 1] + w] : 0);
rk[sa[i]] = (a == b && c == d) ? p : ++p;
}
if (p == n) break;
}
}
후위 자동기 (SAM)
코드 보기
struct State {
int len, link;
unordered_map<char, int> next;
};
State st[MAXLEN * 2];
int sz, last;
string s;
vector<int> children[MAXLEN * 2];
long long ans, f[MAXLEN * 2];
void dfs(int u) {
for (int v : children[u]) {
dfs(v);
f[u] += f[v];
}
if (f[u] > 1) {
ans = max(ans, f[u] * st[u].len);
}
}
void sam_init() {
st[1].len = 0;
st[1].link = -1;
last = sz = 1;
}
void extend(char c) {
int cur = ++sz;
f[cur] = 1;
st[cur].len = st[last].len + 1;
int p = last;
while (p != -1 && !st[p].next.count(c)) {
st[p].next[c] = cur;
p = st[p].link;
}
if (p == -1) {
st[cur].link = 1;
} else {
int q = st[p].next[c];
if (st[p].len + 1 == st[q].len) {
st[cur].link = q;
} else {
int clone = ++sz;
st[clone].len = st[p].len + 1;
st[clone].next = st[q].next;
st[clone].link = st[q].link;
while (p != -1 && st[p].next[c] == q) {
st[p].next[c] = clone;
p = st[p].link;
}
st[q].link = st[cur].link = clone;
}
}
last = cur;
}
void solve() {
cin >> s;
n = s.size();
s = ' ' + s;
sam_init();
for (int i = 1; i <= n; ++i) extend(s[i]);
for (int i = 2; i <= sz; ++i) {
children[st[i].link].push_back(i);
}
dfs(1);
cout << ans << endl;
}
빠른 입출력
코드 보기
namespace FastIO {
char buffer[1024], *in_ptr = buffer, *out_ptr = buffer;
inline char get_char() {
if (in_ptr == out_ptr) {
out_ptr = buffer + fread(buffer, 1, sizeof(buffer), stdin);
in_ptr = buffer;
}
return in_ptr == out_ptr ? EOF : *in_ptr++;
}
inline int read_int() {
int result = 0;
bool negative = false;
char ch = get_char();
while (ch < '0' || ch > '9') {
if (ch == '-') negative = true;
ch = get_char();
}
while (ch >= '0' && ch <= '9') {
result = (result << 3) + (result << 1) + (ch - '0');
ch = get_char();
}
return negative ? -result : result;
}
}
using FastIO::read_int;
다이닉 최대 유량
코드 보기
namespace Dinic {
const int MAXN = 2005;
const int MAXM = 10005;
const int INF = 0x3f3f3f3f;
struct Edge {
int next, to, flow;
};
Edge edges[MAXM * 2];
int head[MAXN], edge_cnt;
int source, sink;
int depth[MAXN];
int current[MAXN];
void init() {
memset(head, 0, sizeof(head));
edge_cnt = 1;
}
void add_edge(int u, int v, int w) {
edges[++edge_cnt] = {head[u], v, w};
head[u] = edge_cnt;
edges[++edge_cnt] = {head[v], u, 0};
head[v] = edge_cnt;
}
bool bfs() {
memset(depth, 0x3f, sizeof(depth));
queue<int> q;
depth[source] = 0;
q.push(source);
while (!q.empty()) {
int u = q.front(); q.pop();
for (int i = head[u]; i; i = edges[i].next) {
int v = edges[i].to;
if (edges[i].flow && depth[v] == INF) {
depth[v] = depth[u] + 1;
q.push(v);
}
}
}
return depth[sink] != INF;
}
int dfs(int u, int flow) {
if (u == sink || !flow) return flow;
int total_flow = 0;
for (int& i = current[u]; i; i = edges[i].next) {
int v = edges[i].to;
if (depth[v] != depth[u] + 1) continue;
int f = dfs(v, min(flow, edges[i].flow));
if (!f) continue;
edges[i].flow -= f;
edges[i ^ 1].flow += f;
total_flow += f;
flow -= f;
if (!flow) break;
}
return total_flow;
}
int max_flow(int s, int t) {
source = s;
sink = t;
int total = 0;
while (bfs()) {
memcpy(current, head, sizeof(current));
total += dfs(source, INF);
}
return total;
}
}
행렬식 계산
코드 보기
int n;
long long mat[MAXN][MAXN];
long long compute_determinant() {
long long res = 1;
int sign = 1;
for (int i = 1; i <= n; ++i) {
for (int j = i + 1; j <= n; ++j) {
while (mat[i][i]) {
long long ratio = mat[j][i] / mat[i][i];
for (int k = i; k <= n; ++k) {
mat[j][k] -= ratio * mat[i][k];
}
swap(mat[i], mat[j]);
sign = -sign;
}
swap(mat[i], mat[j]);
sign = -sign;
}
}
for (int i = 1; i <= n; ++i) {
res = (res * mat[i][i]) % MOD;
}
return (res * sign) % MOD;
}
두교 선 (Du Jiao Sieve)
코드 보기
unordered_map<long long, long long> phi_cache, mu_cache;
long long calc_phi(long long n) {
if (n < MAXN) return prefix_phi[n];
if (phi_cache.count(n)) return phi_cache[n];
long long result = n * (n + 1) / 2;
for (long long l = 2, r; l <= n; l = r + 1) {
r = n / (n / l);
result -= (r - l + 1) * calc_phi(n / l);
}
return phi_cache[n] = result;
}
int calc_mu(long long n) {
if (n < MAXN) return prefix_mu[n];
if (mu_cache.count(n)) return mu_cache[n];
int result = 1;
for (long long l = 2, r; l <= n; l = r + 1) {
r = n / (n / l);
result -= (r - l + 1) * calc_mu(n / l);
}
return mu_cache[n] = result;
}
클래스 오우 알고리즘
코드 보기
long long F(long long a, long long b, long long c, long long n) {
long long res = n * (n + 1) / 2 * (a / c) + (n + 1) * (b / c);
a %= c;
b %= c;
if (a == 0) return res;
long long m = (a * n + b) / c;
return res + n * m - F(c, c - b - 1, a, m - 1);
}
반평면 교차
코드 보기
const double EPS = 1e-10;
struct Point {
double x, y;
Point(double x = 0, double y = 0) : x(x), y(y) {}
};
struct Vector {
double x, y;
Vector(double x = 0, double y = 0) : x(x), y(y) {}
};
Vector operator+(const Vector& a, const Vector& b) {
return Vector(a.x + b.x, a.y + b.y);
}
Vector operator-(const Vector& a, const Vector& b) {
return Vector(a.x - b.x, a.y - b.y);
}
double cross(const Vector& a, const Vector& b) {
return a.x * b.y - a.y * b.x;
}
Point intersection(const Point& a, const Vector& ab, const Point& c, const Vector& cd) {
return a + ab * (cross(cd, a - c) / cross(ab, cd));
}
bool segment_intersect(const Point& a1, const Point& a2, const Point& b1, const Point& b2) {
return cross(a2 - a1, b1 - a1) * cross(a2 - a1, b2 - a1) < 0 &&
cross(b2 - b1, a1 - b1) * cross(b2 - b1, a2 - b1) < 0;
}
int convex_hull(Point* points, int n, Point* hull) {
sort(points + 1, points + n + 1);
int m = 0;
for (int i = 1; i <= n; ++i) {
while (m > 1 && cross(hull[m] - hull[m - 1], points[i] - hull[m - 1]) <= 0) --m;
hull[++m] = points[i];
}
int k = m;
for (int i = n - 1; i >= 1; --i) {
while (m > k && cross(hull[m] - hull[m - 1], points[i] - hull[m - 1]) <= 0) --m;
hull[++m] = points[i];
}
if (n > 1) --m;
return m;
}
void halfplane_intersection() {
// 입력 처리 및 반평면 정렬 후 교차 구하기
// 절차 생략
}
WBLT (Weight-Balanced Tree)
코드 보기
void rotate(int u, int dir) {
if (dir == 0) {
right_child[u] = merge(right_child[left_child[u]], right_child[u]);
left_child[u] = left_child[left_child[u]];
} else {
left_child[u] = merge(left_child[u], left_child[right_child[u]]);
right_child[u] = right_child[right_child[u]];
}
}
void maintain(int u) {
if (size[left_child[u]] > size[right_child[u]] * 3) {
rotate(u, 0);
} else if (size[right_child[u]] > size[left_child[u]] * 3) {
rotate(u, 1);
}
}
int merge(int u, int v) {
if (!u || !v) return u | v;
if (size[u] <= size[v] * 4 && size[v] <= size[u] * 4) {
return update(u, v);
}
if (size[u] >= size[v]) {
down(u);
int l = left_child[u], r = right_child[u];
if (size[l] * 4 >= size[u] + size[v]) return merge(l, merge(r, v));
down(r);
return merge(merge(l, left_child[r]), merge(right_child[r], v));
} else {
down(v);
int l = left_child[v], r = right_child[v];
if (size[r] * 4 >= size[u] + size[v]) return merge(merge(u, l), r);
down(l);
return merge(merge(u, left_child[l]), merge(right_child[l], r));
}
}