Codeforces Global Round 13

Codeforces Global Round 13

A - K-th Largest Value

int a[N];
 
int main() {
    IOS; cin >> n >> m;
    rep (i, 1, n) cin >> a[i], k += a[i];
    rep (i, 1, m) {
        int op, x; cin >> op >> x;
        if (op == 1) {
            a[x] ^= 1;
            if (a[x]) ++k;
            else --k;
        } else {
            cout << (k >= x ? 1 : 0) << '
';
        }
    }
    return 0;
}

## B - Minimal Cost

```c++
int main() {
    IOS;
    for (cin >> _; _; --_) {
        ll u, v, ans = 2e9; cin >> n >> u >> v;
        rep (i, 1, n) cin >> a[i];
        rep (i, 2, n) {
            if (a[i] == a[i - 1]) umin(ans, v + min(u, v));
            else if (abs(a[i] - a[i - 1]) == 1) umin(ans, min(u, v));
            else ans = 0;
        }
        cout << ans << '
';
    }
    return 0;
}

C - Pekora and Trampoline

差分, 可以用树状优化, 没必要

int main() {
    IOS;
    for (cin >> _; _; --_) {
        cin >> n; ll ans = 0;
        rep (i, 1, n) cin >> a[i], b[i] = 0;
	rep (i, 1, n) {
            ans += max(a[i] - 1 - b[i], 0);
	    rep (j, i + 2, min(i + a[i], n)) ++b[j];
	    b[i + 1] += max(b[i] - a[i] + 1, 0);
	}
	cout << ans << "
";
    }
    return 0;
}

D - Zookeeper and The Infinite Zoo

每次都可以将 u 的二进制上的1向左移或将相邻的1替换成1个1, 第0位补0, 即我们可以将 u 末尾的1 任意左移或消去

当从二进制末尾到高位, 任意位置 u 包含 1 的个数 >= v 包含 1 的个数, 即可到达 v

int main() {
    IOS;
    for (cin >> _; _; --_) {
        ll u, v; cin >> u >> v; bool f = 0;
        memset(a, 0, sizeof a); memset(b, 0, sizeof b);
	if (u > v) f = 1;
        for (n = 0; u; a[++n] = (u & 1), u >>= 1);
        for (m = 0; v; b[++m] = (v & 1), v >>= 1);
	    int sa = 0, sb = 0;
	    rep (i, 1, m) {
                sa += a[i]; sb += b[i];
		if (sa < sb) f = 1;
        }
        cout << (!f ? "YES
" : "NO
");
    }
    return 0;
}

E. Fib-tree

二分 + dfs

本质是个二分题, 每次将一棵树尝试分成两颗Fbi树 直到当前这棵树只有一个节点

关键是怎么二分的问题, 二分一棵树, 就是找这棵树的一条边把这颗树分成两部分, 递归 判断这两棵子树是不是Fbi树

然后就是怎么枚举边, 这个就很巧了, 通过dfs枚举当前这棵树的边, 本来dfs就是枚举边和点的, 一边枚举, 一边二分树

注意到一棵树分成两棵Fbi树, 最多有两种分法 (fbi[i] = fbi[i - 1] + fbi[i - 2] = fbi[i - 2] * 2 + fbi[i - 3])

即可找到两棵子孙, 其节点数量为fbi[i - 2]

层数 * 当前子树的边数 * set维护断开了哪些边 即 期望为 (O(2^{logn} * logn * logn) = O(nlog^2n))

int n, m, _, k, cas;
int sz[50][N];
bool st[N];
set<pair<int, int>> v;
VI h[N];

bool work(int x, int fa, int sum, int d) {
    sz[d][x] = 1;
    if (!st[sum]) return 0;
    if (sum == 1) return 1;
    for (auto& y : h[x]) if (y != fa && !v.count({ min(x, y), max(x, y) })) {
        if (work(y, x, sum, d)) return 1;
        sz[d][x] += sz[d][y];
    }
    if (!st[sz[d][x]] || !st[sum - sz[d][x]]) return 0;
    v.insert({ min(x, fa), max(x, fa) });
    if (work(x, 0, sz[d][x], d + 1) && work(fa, 0, sum - sz[d][x], d + 1)) return 1;
    v.erase({ min(x, fa), max(x, fa) }); return 0;
}

int main() {
    IOS; cin >> n;
    for (int i = 0, j = 1; j <= n; st[j] = 1, swap(i += j, j));
    rep (i, 2, n) {
        int u, v; cin >> u >> v;
        h[u].pb(v); h[v].pb(u);
    }
    cout << (work(1, 0, n, 0) ? "YES" : "NO");
    return 0;
}
原文地址:https://www.cnblogs.com/2aptx4869/p/14464269.html