我的算法竞赛模板

2025 年 12 月 30 日 星期二(已编辑)
/
11

我的算法竞赛模板

[TOC]

__builtin

__builtin_clz(a)

std::hypotl

计算 (x,y)(x, y) 平方和开平方根

std::hypotl(x, y)

list

std::list<int> list;
list.push_front(0);
std::vector<std::list<int>::iterator> it(N);
it[0] = list.begin();
for (int i = 1; i < N; i++) {
    int k, p;
    std::cin >> k >> p;
    k--;
    if (p == 0) {
        it[i] = list.insert(it[k], i);
    } else {
        it[i] = list.insert(std::next(it[k]), i);
    }
}

int M;
std::cin >> M;

std::vector<bool> erased(N);

while (M--) {
    int x;
    std::cin >> x;
    x--;
    if (!erased[x]) {
        list.erase(it[x]);
        erased[x] = true;
    }
}

for (int x : list) {
    std::cout << x + 1 << " ";
}

DSU

struct DSU {
    std::vector<int> f, siz;
    
    DSU() {}
    DSU(int n) {
        init(n);
    }
    
    void init(int n) {
        f.resize(n);
        std::iota(f.begin(), f.end(), 0);
        siz.assign(n, 1);
    }
    
    int find(int x) {
        while (x != f[x]) {
            x = f[x] = f[f[x]];
        }
        return x;
    }
    
    bool same(int x, int y) {
        return find(x) == find(y);
    }
    
    bool merge(int x, int y) {
        x = find(x);
        y = find(y);
        if (x == y) {
            return false;
        }
        siz[x] += siz[y];
        f[y] = x;
        return true;
    }
    
    int size(int x) {
        return siz[find(x)];
    }
};

DSU with weight

struct DSU {
    std::vector<int> f, siz;
    std::vector<int> val;
    
    DSU() {}
    DSU(int n) {
        init(n);
    }
    
    void init(int n) {
        f.resize(n);
        std::iota(f.begin(), f.end(), 0);
        siz.assign(n, 1);
        val.resize(n);
    }
    
    int find(int x) {
        if (x == f[x]) {
            return x;
        }
        int root = find(f[x]);
        val[x] += val[f[x]];
        return f[x] = root;
    }
    
    bool same(int x, int y) {
        return find(x) == find(y);
    }
    
    bool merge(int x, int y, int w) {
        int nx = find(x), ny = find(y);
        if (nx == ny) {
            return false;
        }
        
        if (siz[nx] < siz[ny]) {
            std::swap(nx, ny);
            std::swap(x, y);
            w *= -1;
        }

        siz[nx] += siz[ny];
        val[ny] = val[x] + w - val[y];
        f[ny] = nx;

        return true;
    }
    
    int size(int x) {
        return siz[find(x)];
    }
};

DSU with rollback

struct DSU {
    std::vector<int> siz;
    std::vector<int> f;
    std::vector<std::array<int, 2>> his;
    
    DSU(int n) : siz(n + 1, 1), f(n + 1) {
        std::iota(f.begin(), f.end(), 0);
    }
    
    int find(int x) {
        while (f[x] != x) {
            x = f[x];
        }
        return x;
    }
    
    bool same(int x, int y) {
        return find(x) == find(y);
    }
    
    bool merge(int x, int y) {
        x = find(x);
        y = find(y);
        if (x == y) {
            return false;
        }
        if (siz[x] < siz[y]) {
            std::swap(x, y);
        }
        his.push_back({x, y});
        siz[x] += siz[y];
        f[y] = x;
        return true;
    }
    
    int time() {
        return his.size();
    }
    
    void revert(int tm) {
        while (his.size() > tm) {
            auto [x, y] = his.back();
            his.pop_back();
            f[y] = y;
            siz[x] -= siz[y];
        }
    }
};

ST

template<class T, class Cmp = std::less<T>>
struct RMQ {
    const int n;
    const Cmp cmp;
    std::vector<std::vector<T>> a;
    RMQ(const std::vector<T> &init) : n(init.size()), cmp(Cmp()) {
        int lg = std::__lg(n);
        a.assign(n, std::vector<T>(lg + 1));
        for (int j = 0; j <= lg; j++) {
            for (int i = 0; i + (1 << j) <= n; i++) {
                a[i][j] = (j == 0 ? init[i] : std::min(a[i][j - 1], a[i + (1 << (j - 1))][j - 1], cmp));
            }
        }
    }
    T rangeMin(int l, int r) {
        int k = std::__lg(r - l);
        return std::min(a[l][k], a[r - (1 << k)][k], cmp);
    }
};

auto cmpIdx = [](int x, int y) {
        if (key[x] != key[y]) {
            return key[x] > key[y];
        }
        return x > y;
};

二分查找:FFFFFTTTTTT

前驱(第一个T)$[lo, hi)$:

int lo = 1, hi = 1E9;
while (lo < hi) {
    int m = (lo + hi) / 2;
    if (check(m)) {
        hi = m;
    } else {
        lo = m + 1;
    }
}
std::cout << lo << "\n";

后继(最大可行值): TTTTFFFFF(最后一个 T)$[lo, hi]$:

int lo = 1, hi = 1E9;
while (lo < hi) {
    int m = (lo + hi + 1) / 2;
    if (check(m)) {
        lo = m;
    } else {
        hi = m - 1;
    }
}
std::cout << lo << "\n";

partial_sum

前缀和:

std::partial_sum(A.begin(), A.end(), prefix.begin() + 1);

前缀异或和:

std::partial_sum(A.begin(), A.end(), prefix.begin() + 1, [](int a, int b) { return a ^ b; });

后缀和:

std::partial_sum(A.rbegin(), A.rend(), suffix.rbegin() + 1);

int128

std::ostream &operator<<(std::ostream &os, i128 n) {
    if (n == 0) {
        return os << 0;
    }
    std::string s;
    while (n > 0) {
        s += char('0' + n % 10);
        n /= 10;
    }
    std::reverse(s.begin(), s.end());
    return os << s;
}

随机数

std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());

Y conbinator + lambda

bfs + dfs(找环):

int n, a, b;
std::cin >> n >> a >> b;
a--, b--;

std::vector<std::vector<int>> adj(n);
for (int i = 0; i < n; i++) {
    int u, v;
    std::cin >> u >> v;
    u--, v--;
    adj[u].push_back(v);
    adj[v].push_back(u);
}

auto bfs = [&](int s) {
    std::vector<int> dis(n, -1);
    dis[s] = 0;
    std::queue<int> q;
    q.push(s);

    while (!q.empty()) {
        auto x = q.front();
        q.pop();

        for (auto y : adj[x]) {
            if (dis[y] == -1) {
                dis[y] = dis[x] + 1;
                q.push(y);
            }
        }
    }
    return dis;
};

auto dis = bfs(b);

int u = -1;
std::vector<int> vis(n);
std::vector<int> par(n), dep(n);
auto dfs = [&](auto self, int x) -> void {
    vis[x] = true;

    for (auto y : adj[x]) {
        if (!vis[y]) {
            par[y] = x;
            dep[y] = dep[x] + 1;
            self(self, y);
        } else if (dep[y] < dep[x] - 1) {
            for (int i = x; ; i = par[i]) {
                if (u == -1 || dis[i] < dis[u]) {
                    u = i;
                }
                    
                if (i == y) {
                    break;
                }
            }
        }
    }
};
dfs(dfs, 0);

if (bfs(u)[a] > dis[u]) {
    std::cout << "YES\n";
} else {
    std::cout << "NO\n";
}

data structure

fenwick:

0base,add(i, a), sum(i), rangeSum(l, r)

select(x):前缀和不超过 x 的最大位置 +1+1

template <typename T>
struct Fenwick {
    int n;
    std::vector<T> a;
    
    Fenwick(int n_ = 0) {
        init(n_);
    }
    
    void init(int n_) {
        n = n_;
        a.assign(n, T{});
    }
    
    void add(int x, const T &v) {
        for (int i = x + 1; i <= n; i += i & -i) {
            a[i - 1] = a[i - 1] + v;
        }
    }
    
    T sum(int x) {
        T ans{};
        for (int i = x; i > 0; i -= i & -i) {
            ans = ans + a[i - 1];
        }
        return ans;
    }
    
    T rangeSum(int l, int r) {
        return sum(r) - sum(l);
    }
    
    int select(const T &k) {
        int x = 0;
        T cur{};
        for (int i = 1 << std::__lg(n); i; i /= 2) {
            if (x + i <= n && cur + a[x + i - 1] <= k) {
                x += i;
                cur = cur + a[x - 1];
            }
        }
        return x;
    }
};

二维 fenwick

template <typename T>
struct Fenwick {
    int n, m;
    std::vector<std::vector<T>> a;
    
    Fenwick(int n_ = 0, int m_ = 0) {
        init(n_, m_);
    }
    
    void init(int n_, int m_) {
        n = n_, m = m_;
        a.assign(n, std::vector<T>(m_, T{}));
    }
    
    void add(std::pair<int, int> x, const T &v) {
        for (int i = x.first + 1; i <= n; i += i & -i) {
            for (int j = x.second + 1; j <= m; j += j & -j) {
                a[i - 1][j - 1] = a[i - 1][j - 1] + v;
            }
        }
    }
    
    T sum(std::pair<int, int> x) {
        T ans{};
        for (int i = x.first; i > 0; i -= i & -i) {
            for (int j = x.second; j > 0; j -= j & -j) {
                ans = ans + a[i - 1][j - 1];
            }
        }
        return ans;
    }
    
    T rangeSum(std::pair<int, int> x, std::pair<int, int> y) {
        return sum({y.first + 1, y.second + 1}) - sum({y.first + 1, x.second}) - sum({x.first, y.second + 1}) + sum({x.first, x.second});
    }
};

SegmentTree:

template<class Info>
struct SegmentTree {
    int n;
    std::vector<Info> info;
    SegmentTree() : n(0) {}
    SegmentTree(int n_, Info v_ = Info()) {
        init(n_, v_);
    }
    template<class T>
    SegmentTree(std::vector<T> init_) {
        init(init_);
    }
    void init(int n_, Info v_ = Info()) {
        init(std::vector(n_, v_));
    }
    template<class T>
    void init(std::vector<T> init_) {
        n = init_.size();
        info.assign(4 << std::__lg(n), Info());
        std::function<void(int, int, int)> build = [&](int p, int l, int r) {
            if (r - l == 1) {
                info[p] = init_[l];
                return;
            }
            int m = (l + r) / 2;
            build(2 * p, l, m);
            build(2 * p + 1, m, r);
            pull(p);
        };
        build(1, 0, n);
    }
    void pull(int p) {
        info[p] = info[2 * p] + info[2 * p + 1];
    }
    void modify(int p, int l, int r, int x, const Info &v) {
        if (r - l == 1) {
            info[p] = v;
            return;
        }
        int m = (l + r) / 2;
        if (x < m) {
            modify(2 * p, l, m, x, v);
        } else {
            modify(2 * p + 1, m, r, x, v);
        }
        pull(p);
    }
    void modify(int p, const Info &v) {
        modify(1, 0, n, p, v);
    }

    // void rangeOr(int p, int l, int r, int x, int y, int v) {
    //     if (l >= y || r <= x) {
    //         return;
    //     }

    //     if ((info[p].sumAnd & v) == v) {
    //         return;
    //     }

    //     if (r - l == 1) {
    //         int nv = (info[p].sumAnd | v);
    //         info[p] = {nv, nv, std::max(0, nv), std::max(0, nv), std::max(0, nv)};
    //         return;
    //     }

    //     int m = (l + r) / 2;
    //     rangeOr(2 * p, l, m, x, y, v);
    //     rangeOr(2 * p + 1, m, r, x, y, v);
    //     pull(p);
    // }

    // void rangeOr(int l, int r, int v) {
    //     rangeOr(1, 0, n, l, r, v);
    // }

    Info rangeQuery(int p, int l, int r, int x, int y) {
        if (l >= y || r <= x) {
            return Info();
        }
        if (l >= x && r <= y) {
            return info[p];
        }
        int m = (l + r) / 2;
        return rangeQuery(2 * p, l, m, x, y) + rangeQuery(2 * p + 1, m, r, x, y);
    }
    Info rangeQuery(int l, int r) {
        return rangeQuery(1, 0, n, l, r);
    }

    template<class F>
    int findFirst(int p, int l, int r, int x, int y, F &&pred) {
        if (l >= y || r <= x) {
            return -1;
        }
        if (l >= x && r <= y && !pred(info[p])) {
            return -1;
        }
        if (r - l == 1) {
            return l;
        }
        int m = (l + r) / 2;
        int res = findFirst(2 * p, l, m, x, y, pred);
        if (res == -1) {
            res = findFirst(2 * p + 1, m, r, x, y, pred);
        }
        return res;
    }
    template<class F>
    int findFirst(int l, int r, F &&pred) {
        return findFirst(1, 0, n, l, r, pred);
    }
    
    template<class F>
    int findLast(int p, int l, int r, int x, int y, F &&pred) {
        if (l >= y || r <= x) {
            return -1;
        }
        if (l >= x && r <= y && !pred(info[p])) {
            return -1;
        }
        if (r - l == 1) {
            return l;
        }
        int m = (l + r) / 2;
        int res = findLast(2 * p + 1, m, r, x, y, pred);
        if (res == -1) {
            res = findLast(2 * p, l, m, x, y, pred);
        }
        return res;
    }
    template<class F>
    int findLast(int l, int r, F &&pred) {
        return findLast(1, 0, n, l, r, pred);
    }
};

constexpr i64 inf = 1E18 + 1;

struct Info {
    i64 sum = 0;
    int sumAnd = ~0;
    i64 maxSub = -inf;
    i64 pre = -inf;
    i64 suf = -inf;
};

Info operator+ (const Info &a, const Info &b) {
    Info c;
    c.sum = a.sum + b.sum;
    c.sumAnd = a.sumAnd & b.sumAnd;
    c.maxSub = std::max({a.suf + b.pre, a.maxSub, b.maxSub});
    c.pre = std::max(a.pre, a.sum + b.pre);
    c.suf = std::max(b.suf, a.suf + b.sum);
    return c;
}

LazySegmentTree:

template<class Info, class Tag>
struct LazySegmentTree {
    int n;
    std::vector<Info> info;
    std::vector<Tag> tag;
    LazySegmentTree() : n(0) {}
    LazySegmentTree(int n_, Info v_ = Info()) {
        init(n_, v_);
    }
    template<class T>
    LazySegmentTree(std::vector<T> init_) {
        init(init_);
    }
    void init(int n_, Info v_ = Info()) {
        init(std::vector(n_, v_));
    }
    template<class T>
    void init(std::vector<T> init_) {
        n = init_.size();
        info.assign(4 << std::__lg(n), Info());
        tag.assign(4 << std::__lg(n), Tag());
        std::function<void(int, int, int)> build = [&](int p, int l, int r) {
            if (r - l == 1) {
                info[p] = init_[l];
                return;
            }
            int m = (l + r) / 2;
            build(2 * p, l, m);
            build(2 * p + 1, m, r);
            pull(p);
        };
        build(1, 0, n);
    }
    void pull(int p) {
        info[p] = info[2 * p] + info[2 * p + 1];
    }
    void apply(int p, const Tag &v) {
        info[p].apply(v);
        tag[p].apply(v);
    }
    void push(int p) {
        apply(2 * p, tag[p]);
        apply(2 * p + 1, tag[p]);
        tag[p] = Tag();
    }
    void modify(int p, int l, int r, int x, const Info &v) {
        if (r - l == 1) {
            info[p] = v;
            return;
        }
        int m = (l + r) / 2;
        push(p);
        if (x < m) {
            modify(2 * p, l, m, x, v);
        } else {
            modify(2 * p + 1, m, r, x, v);
        }
        pull(p);
    }
    void modify(int p, const Info &v) {
        modify(1, 0, n, p, v);
    }
    Info rangeQuery(int p, int l, int r, int x, int y) {
        if (l >= y || r <= x) {
            return Info();
        }
        if (l >= x && r <= y) {
            return info[p];
        }
        int m = (l + r) / 2;
        push(p);
        return rangeQuery(2 * p, l, m, x, y) + rangeQuery(2 * p + 1, m, r, x, y);
    }
    Info rangeQuery(int l, int r) {
        return rangeQuery(1, 0, n, l, r);
    }
    void rangeApply(int p, int l, int r, int x, int y, const Tag &v) {
        if (l >= y || r <= x) {
            return;
        }
        if (l >= x && r <= y) {
            apply(p, v);
            return;
        }
        int m = (l + r) / 2;
        push(p);
        rangeApply(2 * p, l, m, x, y, v);
        rangeApply(2 * p + 1, m, r, x, y, v);
        pull(p);
    }
    void rangeApply(int l, int r, const Tag &v) {
        return rangeApply(1, 0, n, l, r, v);
    }
    
    template<class F>
    int findFirst(int p, int l, int r, int x, int y, F &&pred) {
        if (l >= y || r <= x) {
            return -1;
        }
        if (l >= x && r <= y && !pred(info[p])) {
            return -1;
        }
        if (r - l == 1) {
            return l;
        }
        int m = (l + r) / 2;
        push(p);
        int res = findFirst(2 * p, l, m, x, y, pred);
        if (res == -1) {
            res = findFirst(2 * p + 1, m, r, x, y, pred);
        }
        return res;
    }
    template<class F>
    int findFirst(int l, int r, F &&pred) {
        return findFirst(1, 0, n, l, r, pred);
    }
    template<class F>
    int findLast(int p, int l, int r, int x, int y, F &&pred) {
        if (l >= y || r <= x) {
            return -1;
        }
        if (l >= x && r <= y && !pred(info[p])) {
            return -1;
        }
        if (r - l == 1) {
            return l;
        }
        int m = (l + r) / 2;
        push(p);
        int res = findLast(2 * p + 1, m, r, x, y, pred);
        if (res == -1) {
            res = findLast(2 * p, l, m, x, y, pred);
        }
        return res;
    }
    template<class F>
    int findLast(int l, int r, F &&pred) {
        return findLast(1, 0, n, l, r, pred);
    }
};

struct Tag {
    int x = 0;
    void apply(const Tag &t) & {
        x = std::max(x, t.x);
    }
};

struct Info {
    int x = 0;
    void apply(const Tag &t) & {
        x = std::max(x, t.x);
    }
};

Info operator+(const Info &a, const Info &b) {
    return {std::max(a.x, b.x)};
}

欧拉筛:

std::vector<int> minp, primes;

void sieve(int n) {
    minp.assign(n + 1, 0);
    primes.clear();
    
    for (int i = 2; i <= n; i++) {
        if (minp[i] == 0) {
            minp[i] = i;
            primes.push_back(i);
        }
        
        for (auto p : primes) {
            if (i * p > n) {
                break;
            }
            minp[i * p] = p;
            if (p == minp[i]) {
                break;
            }
        }
    }
}

bool isprime(int n) {
    return minp[n] == n;
}

离散化:

std::sort(v.begin(), v.end());
v.erase(std::unique(v.begin(), v.end()), v.end());
for (int i = 0; i < n; i++) {
    a[i] = std::lower_bound(v.begin(), v.end(), a[i]) - v.begin();
}

双指针

for (int x = 0, y = -1; x <= n; x++) {
    if (x < n && s[x] == 'A') {
        ans++;
    } else {
        min = std::min(min, x - y - 1);
        y = x;
    }
}

单调栈

std::vector<int> stk;
for (int i = 0; i < N; i++) {
    while (!stk.empty() && A[i] > A[stk.back()]) {
        stk.pop_back();
    }

    if (!stk.empty()) {
        ans[i] = -1;
    } else {
        ans[i] = stk.back();
    }
    stk.push_back(i);
}

单调队列

std::deque<int> q;
for (int i = 0; i < n; i++) {
    while (!q.empty() && a[i] >= a[q.back()]) {
        q.pop_back();
    }
    q.push_back(i);
    if (i - q.front() > k - 1) {
        q.pop_front();
    }
    if (i >= k - 1) {
        max[i] = a[q.front()];
    }
}

二维单调队列

std::vector<std::vector<int>> rowMin(a, std::vector<int>(b - n + 1)), rowMax(a, std::vector<int>(b - n + 1));
for (int x = 0; x < a; x++) {
    std::deque<int> qMin, qMax;
    for (int y = 0; y < b; y++) {
        while (!qMin.empty() && g[x][y] <= g[x][qMin.back()]) {
            qMin.pop_back();
        }
        qMin.push_back(y);
        if (y - qMin.front() > n - 1) {
            qMin.pop_front();
        }
        if (y >= n - 1) {
            rowMin[x][y - n + 1] = g[x][qMin.front()];
        }
    }

    for (int y = 0; y < b; y++) {
        while (!qMax.empty() && g[x][y] >= g[x][qMax.back()]) {
            qMax.pop_back();
        }
        qMax.push_back(y);
        if (y - qMax.front() > n - 1) {
            qMax.pop_front();
        }
        if (y >= n - 1) {
            rowMax[x][y - n + 1] = g[x][qMax.front()];
        }
    }
}

std::vector<std::vector<int>> min(a - n + 1, std::vector<int>(b - n + 1)), max(a - n + 1, std::vector<int>(b - n + 1));
for (int y = 0; y < b - n + 1; y++) {
    std::deque<int> qMin, qMax;
    for (int x = 0; x < a; x++) {
        while (!qMin.empty() && rowMin[x][y] <= rowMin[qMin.back()][y]) {
            qMin.pop_back();
        }
        qMin.push_back(x);
        if (x - qMin.front() > n - 1) {
            qMin.pop_front();
        }
        if (x >= n - 1) {
            min[x - n + 1][y] = rowMin[qMin.front()][y];
        }
    }
    for (int x = 0; x < a; x++) {
        while (!qMax.empty() && rowMax[x][y] >= rowMax[qMax.back()][y]) {
            qMax.pop_back();
        }
        qMax.push_back(x);
        if (x - qMax.front() > n - 1) {
            qMax.pop_front();
        }
        if (x >= n - 1) {
            max[x - n + 1][y] = rowMax[qMax.front()][y];
        }
    }
}

dijkstra

std::vector<std::vector<std::pair<int, i64>>> g(n);
for (int i = 0; i < m; i++) {
    int u, v;
    i64 w;
    std::cin >> u >> v >> w;
    u--;
    v--;
    g[u].push_back({v, w});
    g[v].push_back({u, w});
}

    
std::vector<i64> dis(n, INF);
std::priority_queue<std::pair<i64,int>, std::vector<std::pair<i64,int>>, std::greater<std::pair<i64,int>>> pq;

pq.emplace(0, T);
dis[T] = 0;
while (!pq.empty()) {
    i64 d = pq.top().first;
    int u = pq.top().second;
    pq.pop();
    if (d != dis[u]) {
        continue;
    }
    for (int i = 0; i < g[u].size(); i++) {
        int v = g[u][i].first;
        i64 w = g[u][i].second;
        if (dis[v] > d + w) {
            dis[v] = d + w;
            pq.emplace(dis[v], v);
        }
    }
}

dijkstra:

#include <bits/stdc++.h>

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n, t;
    std::cin >> n >> t;

    std::vector<std::vector<std::pair<int, int>>> adj(n);
    for (int i = 0; i < t; i++) {
        int m;
        std::cin >> m;

        for (int j = 0; j < m; j++) {
            int u, v;
            std::cin >> u >> v;
            u--;
            v--;
            adj[u].emplace_back(v, i);
            adj[v].emplace_back(u, i);
        }
    }

    int k;
    std::cin >> k;

    std::vector<std::vector<int>> pos(t);
    for (int i = 0; i < k; i++) {
        int a;
        std::cin >> a;
        a--;
        pos[a].push_back(i);
    }

    std::priority_queue<std::pair<int, int>, std::vector<std::pair<int, int>>, std::greater<>> q;
    q.emplace(0, 0);
    std::vector<int> dis(n, -1);

    while (!q.empty()) {
        auto [d, x] = q.top();
        q.pop();

        if (dis[x] != -1) {
            continue;
        }
        dis[x] = d;

        for (auto [y, i] : adj[x]) {
            auto it = std::lower_bound(pos[i].begin(), pos[i].end(), d);
            if (it != pos[i].end()) {
                q.emplace(*it + 1, y);
            }
        }
    }

    std::cout << dis[n - 1] << "\n";

    return 0;
}

trie 树

#include <bits/stdc++.h>

using i64 = long long;

constexpr int N = 1E6 + 10;

int tot = 1;
int trie[N][26];
int cnt[N];


int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n;
    std::cin >> n;

    std::vector<std::string> s(n);
    i64 ans = 0;
    for (int i = 0; i < n; i++) {
        std::cin >> s[i];
        ans += s[i].size();

        int p = 1;
        for (auto c : s[i]) {
            int &q = trie[p][c - 'a'];
            if (!q) {
                q = ++tot;
            }
            p = q;
            cnt[p] += 1;
        }
    }

    ans *= 2 * n;
    for (int i = 0; i < n; i++) {
        std::reverse(s[i].begin(), s[i].end());

        int p = 1;
        for (auto c : s[i]) {
            int &q = trie[p][c - 'a'];
            if (!q) {
                break;
            }
            p = q;
            ans -= 2 * cnt[p];
        }
    }

    std::cout << ans << "\n";

    return 0;
}

公式

平方和: $$ 1^2 + 2^2 + 3^2 + \dots + n^2 = \frac{n(n + 1)(2n + 1)}{6} $$ __builtin_popcount(x): x 二进制下,$1$ 的个数。

组合数:

/**   组合数(小范围预处理,逆元+杨辉三角)
 *    2024-03-14: https://qoj.ac/submission/353877
 *    2023-10-06: https://qoj.ac/submission/203196
**/
constexpr int P = 1000000007;
constexpr int L = 10000;

int fac[L + 1], invfac[L + 1];
int sumbinom[L + 1][7];

int binom(int n, int m) {
    if (n < m || m < 0) {
        return 0;
    }
    return 1LL * fac[n] * invfac[m] % P * invfac[n - m] % P;
}

int power(int a, int b) {
    int res = 1;
    for (; b; b /= 2, a = 1LL * a * a % P) {
        if (b % 2) {
            res = 1LL * res * a % P;
        }
    }
    return res;
}

int main() {
    fac[0] = 1;
    for (int i = 1; i <= L; i++) {
        fac[i] = 1LL * fac[i - 1] * i % P;
    }
    invfac[L] = power(fac[L], P - 2);
    for (int i = L; i; i--) {
        invfac[i - 1] = 1LL * invfac[i] * i % P;
    }

    sumbinom[0][0] = 1;
    for (int i = 1; i <= L; i++) {
        for (int j = 0; j < 7; j++) {
            sumbinom[i][j] = (sumbinom[i - 1][j] + sumbinom[i - 1][(j + 6) % 7]) % P;
        }
    }
}

使用社交账号登录

  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Loading...