2025년 상반기 알고리즘 템플릿 모음

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));
    }
}

태그: AC자동화 사전순배열 후위자동기 다이닉 행렬식

7월 28일 15:27에 게시됨