# Technocup 2021 - Elimination Round 2

A - Prison Break

四个角贪心

int main() {
    IOS;
    for (cin >> _; _; --_) {
        int a, b, x, y; cin >> a >> b >> x >> y;
        int ans = max(a - x + b - y, a - x + y - 1);
        umax(ans, x + y - 2); umax(ans, x - 1 + b - y);
        cout << ans << '\n';
    }
    return 0;
}

B - Repainting Street

又是分段模拟

int main() {
    IOS;
    for (cin >> _; _; --_) {
        cin >> n >> k;
        int ls = 0, ans = 1e9;
        unordered_map<int, vector<PII>> st;
        rep (i, 1, n) {
            cin >> m;
            if (ls != m) st[m].pb({ i, i });
            else ++st[m].back().se;
            ls = m;
        }
        for (auto &i : st) {
            int res = 0, ls = 0, c;
            if (i.se[0].fi != 1) {
                c = i.se[0].fi - 1;
                res = (c - 1) / k + 1; ls = c % k ? k - c % k : 0;
            }
            rep (j, 1, i.se.size() - 1) {
                ls = max(0, ls - i.se[j - 1].se + i.se[j - 1].fi - 1);
                c = i.se[j].fi - i.se[j - 1].se - 1 - ls;
                if (c > 0) res += (c - 1) / k + 1, ls = c % k ? k - c % k : 0;
                else ls = -c;
            }
            if (i.se.back().se != n) {
                ls = max(0, ls - i.se.back().se + i.se.back().fi - 1);
                c = n - i.se.back().se - ls;
                if (c > 0) res += (c - 1) / k + 1; 
            }
            umin(ans, res);
        }
        cout << ans << '\n';
    }
    return 0;
}

C - Bouncing Ball

dp, f[i] 表示从 i 开始弹, 弹出游戏最大长度所需的花费

ll f[N];
char s[N];
 
int main() {
    IOS;
    for (cin >> _; _; --_) {
        ll n, k, p, x, y; cin >> n >> p >> k >> s + 1 >> x >> y;
        per (i, n, 1) f[i] = (i + k > n ? 0 : f[i + k]) + (s[i] ^ '0' ? 0 : x);
        ll ans = 2e18;
        rep (i, 1, n + 1 - p) umin(ans, f[i + p - 1] + (i - 1ll) * y);
        cout << ans << '\n';
    }
    return 0;
}

D - XOR-gun

XOR, 肯定往二进制想, 思考得到我们要找个的位置 i

使得 [l, i] > [i + 1, r] 其中 i - l + r - i - 1 最小, [l, r] 表示合并 l~r 区间

明显会超时, \(n^3\), 但是注意到,

两个相邻的数二进制最高位相同则会得到一个比原先小的数, 如果其两边存在一个数最高位跟这两个数相同, 答案直接是 1

通过二进制只有31位, 排除复杂情况, 降低复杂度

将这种情况排除, 则 n就会缩小到 31 * 2, \(n^3\) 也无所谓

这道题让我想起了 这场的E, 为什么我的线段树不会超时呢?

懂了这道题, 应该能想明白的

int main() {
    IOS; cin >> n; m = n;
    rep (i, 1, n) {
        cin >> a[i]; ++b[__builtin_clz(a[i])];
        a[i] ^= a[i - 1];
    }
    rep (i, 0, 31) if (b[i] > 2) { cout << 1; return 0; }
    rep (l, 1, n - 1) rep (r, l + 1, n) rep (k, l, r - 1)
        if ((a[k] ^ a[l - 1]) > (a[r] ^ a[k])) umin(m, r - l - 1);
    cout << (m == n ? -1 : m);
    return 0;
}

E - New Game Plus!

每个boss_i的贡献为, \(c_i * (n - i)\), 明显贪心的, 要从大到小排序, 直接扫一遍就行

对于 k > 0, 即清空所有的 赏金, 相当于重新开始游戏

即 你可以将 n 个boss 最多分成 k + 1 个游戏, 使得分最高

当然对于一个游戏, boss 越多, 前几个boss 的贡献就越大, 即设当前 赏金为 x

则向 这个游戏添加一个 \(boss_j\), 则获得积分为 x * (\(curNumberOfBoss\)), 赏金变为 \(x += c_j\)

这不是明显吗, 已经贪过心, 每次将 \(boss_i\) 添加到任何一个游戏(k + 1)的末尾, 使得 x 最大即可, 那不就是优先队列吗?

妙啊

int main() {
    IOS; cin >> n >> m;
    rep (i, 1, n) cin >> a[i];
    sort(a + 1, a + 1 + n, greater<int>());
    ll ans = 0; priority_queue<ll> q(m + 1, 0);
    rep (i, 1, n) {
        ll c = q.top(); q.pop();
        q.push(c + a[i]); ans += c;
    }
    cout << ans;
    return 0;
}
posted @ 2020-11-29 22:32  洛绫璃  阅读(195)  评论(0编辑  收藏  举报