2021杭电多校8

2021“MINIEYE杯”中国大学生算法设计超级联赛(8)

A

B

C

\(n=5000\) 的完全图求最小生成树的最长边长度。堆优化的 Prim 复杂度 \(O(m\log n)\),Kruskal 复杂度 \(O(m\log m)\),都过不去。只有朴素的 Prim 算法 \(O(n^2)\) 可以过去。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e3 + 5;
using ll = long long;
const ll inf = 0x3f3f3f3f3f3f3f3f;

int x[maxn], y[maxn];
namespace Prim {
ll g[maxn][maxn], dis[maxn];
int vis[maxn];
ll naivePrim(int n) {
    memset(dis, 0x3f, sizeof(ll) * (n + 1));
    memset(vis, 0, sizeof(int) * (n + 1));
    int cnt = 1, u = 1;
    ll res = 0;
    vis[1] = 1;
    while (cnt < n) {
        ll now = inf, v = 0;
        for (int i = 1; i <= n; ++i) {
            if (vis[i])
                continue;
            ll tmp = g[u][i];
            if (tmp < dis[i]) {
                dis[i] = tmp;
                vis[i] = 0;
            }
            if (dis[i] < now)
                now = dis[v = i];
        }
        res = max(res, now);
        vis[u = v] = 1;
        cnt++;
    }
    return res;
}
}; // namespace Prim
using namespace Prim;
void solve() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i)
        cin >> x[i] >> y[i];
    function<ll(int, int)> calc = [&](int a, int b) -> ll {
        ll dx = x[a] - x[b], dy = y[a] - y[b];
        return (dx * dx + dy * dy);
    };
    for (int i = 1; i < n; ++i) {
        for (int j = i + 1; j <= n; ++j) {
            g[i][j] = g[j][i] = calc(i, j);
        }
    }
    cout << naivePrim(n) << '\n';
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);
    int T = 1;
    cin >> T;
    while (T--)
        solve();
    return 0;
}

D

对序列进行三种操作:

  1. \([l,r]\) 内每个数减去 \(\text{lowbit}\)
  2. \([l,r]\) 内每个数加上最高位
  3. \([l,r]\) 区间和

容易想到把每个数拆成最高位和剩下的部分,用两棵线段树分别维护。此时操作 1 就可以暴力修改叶子,如果减到 \(0\) 了就把高位线段树的相应位置变成 \(0\);操作 2 用一棵区间乘 + 区间赋值 + 区间和线段树就可以维护。这样每次操作线段树的均摊复杂度应该是 \(\Theta(\log^2 n)\)。求和的时候用快速幂也能过,如果事先预处理出 \(2\) 的幂会更快一些(967ms -> 826ms)。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
using ll = long long;
const ll inf = 0x3f3f3f3f3f3f3f3f;
const ll mod = 998244353;
ll lowbit(ll x) { return x & (-x); }
ll pow2[maxn << 1];
namespace sgt_high {
int tag[maxn << 2];
bool flag[maxn << 2];
ll sum[maxn << 2];
void push_up(int p) {
    sum[p] = (sum[p << 1] + sum[p << 1 | 1]) % mod;
    flag[p] = (flag[p << 1] & flag[p << 1 | 1]);
}
void build(int p, int l, int r, int *a) {
    sum[p] = 0, flag[p] = 0, tag[p] = 0;
    if (l == r) {
        sum[p] = a[l];
        return;
    }
    int mid = (l + r) >> 1;
    build(p << 1, l, mid, a);
    build(p << 1 | 1, mid + 1, r, a);
    push_up(p);
}
void push_down(int p) {
    tag[p << 1] += tag[p];
    tag[p << 1 | 1] += tag[p];
    sum[p << 1] = sum[p << 1] * pow2[tag[p]] % mod;
    sum[p << 1 | 1] = sum[p << 1 | 1] * pow2[tag[p]] % mod;
    tag[p] = 0;
}
void assign(int p, int l, int r, int x, int y) {
    if (flag[p])
        return;
    if (x <= l && r <= y) {
        flag[p] = 1;
        sum[p] = 0;
        return;
    }
    if (tag[p])
        push_down(p);
    int mid = (l + r) >> 1;
    if (x <= mid)
        assign(p << 1, l, mid, x, y);
    if (y > mid)
        assign(p << 1 | 1, mid + 1, r, x, y);
    push_up(p);
}
void modify(int p, int l, int r, int x, int y) {
    if (flag[p]) {
        return;
    }
    if (x <= l && r <= y) {
        sum[p] = sum[p] * 2 % mod;
        tag[p]++;
        return;
    }
    if (tag[p])
        push_down(p);
    int mid = (l + r) >> 1;
    if (x <= mid)
        modify(p << 1, l, mid, x, y);
    if (y > mid)
        modify(p << 1 | 1, mid + 1, r, x, y);
    push_up(p);
}
ll query(int p, int l, int r, int x, int y) {
    if (flag[p])
        return 0;
    if (x <= l && r <= y) {
        return sum[p] % mod;
    }
    ll ret = 0;
    int mid = (l + r) >> 1;
    if (tag[p])
        push_down(p);
    if (x <= mid)
        ret = (ret + query(p << 1, l, mid, x, y)) % mod;
    if (y > mid)
        ret = (ret + query(p << 1 | 1, mid + 1, r, x, y)) % mod;
    return ret;
}
}; // namespace sgt_high
namespace sgt_low {
int tag[maxn << 2];   // tag : subtree[p] -= lowbit[p]
bool flag[maxn << 2]; // subtree[p] = 0 ? 1 : 0
ll sum[maxn << 2];
void push_up(int p) {
    sum[p] = (sum[p << 1] + sum[p << 1 | 1]) % mod;
    flag[p] = (flag[p << 1] & flag[p << 1 | 1]);
}
void build(int p, int l, int r, int *a) {
    sum[p] = 0, flag[p] = 0, tag[p] = 0;
    if (l == r) {
        sum[p] = a[l];
        if (sum[p] == 0)
            flag[p] = 1;
        return;
    }
    int mid = (l + r) >> 1;
    build(p << 1, l, mid, a);
    build(p << 1 | 1, mid + 1, r, a);
    push_up(p);
}
void modify(int p, int l, int r, int x, int y, int n) {
    if (x <= l && r <= y && flag[p]) {
        sgt_high::assign(1, 1, n, l, r);
        return;
    }
    if (l == r) {
        sum[p] -= lowbit(sum[p]);
        if (sum[p] == 0)
            flag[p] = 1;
        return;
    }
    int mid = (l + r) >> 1;
    if (x <= mid)
        modify(p << 1, l, mid, x, y, n);
    if (y > mid)
        modify(p << 1 | 1, mid + 1, r, x, y, n);
    push_up(p);
}
ll query(int p, int l, int r, int x, int y) {
    if (x <= l && r <= y) {
        return sum[p] % mod;
    }
    ll ret = 0;
    int mid = (l + r) >> 1;
    if (x <= mid)
        ret = (ret + query(p << 1, l, mid, x, y)) % mod;
    if (y > mid)
        ret = (ret + query(p << 1 | 1, mid + 1, r, x, y)) % mod;
    return ret;
}
}; // namespace sgt_low
int a[maxn], b[maxn];
void solve() {
    int n, q;
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
    }
    for (int i = 1, x; i <= n; ++i) {
        x = 31 - __builtin_clz(a[i]);
        a[i] -= (1 << x), b[i] = (1 << x);
    }
    sgt_high::build(1, 1, n, b);
    sgt_low::build(1, 1, n, a);
    cin >> q;
    for (int i = 1, op, l, r; i <= q; ++i) {
        cin >> op >> l >> r;
        if (op == 1) {
            ll res = sgt_low::query(1, 1, n, l, r);
            res += sgt_high::query(1, 1, n, l, r);
            cout << res % mod << '\n';
        } else if (op == 2) {
        	sgt_low::modify(1, 1, n, l, r, n);
        } else {
        	sgt_high::modify(1, 1, n, l, r);
        }
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);
    pow2[0] = 1;
    for (int i = 1; i <= 200000; ++i) {
        pow2[i] = pow2[i - 1] << 1;
        if (pow2[i] >= mod)
            pow2[i] -= mod;
    }
    int T = 1;
    cin >> T;
    while (T--)
        solve();
    return 0;
}

E

F

队友写的,好像可以转化成 nim 的结论,还要用线性筛搞一下。

G

H

队友写的计算几何。

I

队友写的哈希。

J

posted @ 2021-11-07 16:30  Theophania  阅读(50)  评论(0)    收藏  举报