Educational Codeforces Round 101 (Rated for Div. 2)

Educational Codeforces Round 101 (Rated for Div. 2)

A - Regular Bracket Sequence

最多有一对 (), 判断完事

int main() {
    IOS;
    for (cin >> _; _; --_) {
        string s; cin >> s;
        if (s.size() % 2 || s[0] == ')' || s.back() == '(') cout << "NO\n";
        else cout << "YES\n";
    }
    return 0;
}

B - Red and Blue

贪心找两个序列的最大前缀和

int main() {
    IOS;
    for (cin >> _; _; --_) {
        cin >> n; int x = 0, y = 0;
        for (int s = 0, i = 1; i <= n; ++i) cin >> k, s += k, umax(x, s);
        cin >> n;
        for (int s = 0, i = 1; i <= n; ++i) cin >> k, s += k, umax(y, s);
        cout << x + y << '\n';
    }
    return 0;
}

C - Building a Fence

按顺序找出当前 i 可以放的最高和最低位置, 再按提议判断即可

int main() {
    IOS;
    for (cin >> _; _; --_) {
        cin >> n >> k >> m;
        int x = m, y = m; bool f = 1;
        rep (i, 2, n) {
            cin >> m;
            x = min(x + k - 1, m + k - 1);
            y = max(y - k + 1, m);
            if (x < y) f = 0;
        }
        if (y != m || !f) cout << "NO\n";
        else cout << "YES\n";
    }
    return 0;
}

D - Ceil Divisions

明显能想到一个数用比它大的数变成 1, 但剩下最大数无法处理

只给你了n + 5, 明显让你在5次之内变成 1, 而 sqrt(n - 1) + 1 刚好 2 次

然后 sqrt(n - 1) + 1 成为了最大数, 在按上面操作, 而最多开5次根号, 刚刚好(1, 2还不用变呢 n + 3就够了)

int main() {
    IOS;
    for (cin >> _; _; --_) {
        cin >> n; VI a(1, n);
        while (a.back() != 2) a.pb(sqrt(a.back() - 1) + 1);
        cout << n - 3 + a.size() << '\n';
        for (int i = n, j = 0; i > 2; --i)
            if (i == a[j]) ++j;
            else cout << i << ' ' << n << '\n';
        rep (i, 1, a.size() - 1) rep (j, 0, 1) cout << a[i - 1] << ' ' << a[i] << '\n';
    }
    return 0;
}

E - A Bit Similar

一看字符串里找字符串就先把 sam 板子仍上去, 然而1e6 咋办呢

最多有1e6个字串, 也就是说最多能完全覆盖长度为 log2(1e6) 的01串, 在sam上贪心爆搜完事

当然肯定有不用sam的方法, div2不怎么考数据结构的, 能用板子直接扔最好了

struct SAM { //不管是不是多组数据都调用init
    static const int N = 1e6 + 5, M = 2;
    struct node { int fa, len, ne[M]; } tr[N << 1];
    int sz, las;
    void init() {
        rep(i, 1, sz)
            tr[i].len = tr[i].fa = 0, memset(tr[i].ne, 0, sizeof tr[i].ne);
        sz = las = 1;
    }
    void add(int ch) {
        int p = las, cur = las = ++sz;
        tr[cur].len = tr[p].len + 1;
        for (; p && !tr[p].ne[ch]; p = tr[p].fa) tr[p].ne[ch] = cur;
        if (p == 0) { tr[cur].fa = 1; return; }
        int q = tr[p].ne[ch];
        if (tr[q].len == tr[p].len + 1) { tr[cur].fa = q; return; }
        int nq = ++sz; tr[nq] = tr[q]; tr[nq].len = tr[p].len + 1;
        for (; p && tr[p].ne[ch] == q; p = tr[p].fa) tr[p].ne[ch] = nq;
        tr[q].fa = tr[cur].fa = nq;
    }
    void build(char* s) {
        for (int i = 0; s[i]; ++i) add(s[i] - '0');
    }
    bool match(char* s) {
        for (int i = 0, ch = s[i] - '0', p = 1; s[i]; ch = s[++i] - '0')
            if (tr[p].ne[ch]) p = tr[p].ne[ch];
            else return 0;
        return 1;
    }
} sam;
 
const int N = 1e6 + 5;
 
int n, m, _, k;
char s[N], t[N];
 
bool check(int x = 0) {
    if (x == k) { t[x] = '\0'; return !sam.match(t); }
    t[x] = '1';
    if (check(x + 1)) return 1;
    t[x] = '0';
    return check(x + 1);
}
 
int main() {
    IOS;
    for (cin >> _; _; --_) {
        cin >> n >> k >> s;
        if (n == k) { 
            cout << "YES\n"; bool f = 0;
            rep (i, 0, n - 2) f = f || s[i] == '0', s[i] = '0';
            if (f) s[n - 1] = '0';
            cout << s << '\n';
            continue;
        }
        m = log2(n - k) + 1; sam.init(); sam.build(s);
        if (!check()) { cout << "NO\n"; continue; }
        cout << "YES\n";
        for (int i = 0; t[i]; ++i) t[i] = t[i] - '0' ? '0' : '1';
        rep(i, 0, k - 1) if (!t[i]) t[i] = '0'; t[n] = '\0';
        cout << t << '\n';
    }
    return 0;
}

F - Power Sockets

还是板子题, 贪心放就好了, 去出没用过的链, 平分两份, 放在树上深度最小的点上, 找就行了

复杂度 \(O(nlog^2n)\) 4s够了

ll c[2][N + 1], ans = 2e18;
 
void add(int x, ll k) {
    for (int i = x; i <= N; i += -i & i) c[0][i] += k, c[1][i] += x * k;
}
 
void add(int l, int r, ll k) { add(l, k); add(r + 1, -k); }
 
ll ask(int x) {
    ll p = 0, q = 0, f = x + 1;
    for (; x; x -= -x & x) p += c[0][x], q += c[1][x];
    return p * f - q;
}
 
ll ask(int l, int r) { return ask(r) - ask(l - 1); }
 
ll kth(int k) {
    if (ask(N) < k) return 2e18;
    int l = 1, r = N;
    while (l < r) {
        ll mid = l + r >> 1, c;
        if ((c = ask(l, mid)) < k) k -= c, l = mid + 1;
        else r = mid; 
    }
    return l;
}
 
int main() {
    IOS; cin >> n >> k; VI a(n);
    for (auto &i : a) cin >> i, --i; sort(all(a));
    add(2, 2 + a.back() >> 1, 1); add(2, 2 + a.back() + 1 >> 1, 1); umin(ans, kth(k));
    per (i, n - 2, 0) {
        int cur = kth(1); add(cur, cur, -1);
        add(cur + 2, 1 + cur + (a[i] >> 1), 1); add(cur + 2, 1 + cur + (a[i] + 1 >> 1), 1);
        umin(ans, kth(k));
    }
    cout << (ans == 2e18 ? -1 : ans);
    return 0;
}
posted @ 2021-01-07 21:24  洛绫璃  阅读(133)  评论(0编辑  收藏  举报