1. 程式人生 > 實用技巧 >Codeforces Round #692 (Div. 2, based on Technocup 2021 Elimination Round 3)

Codeforces Round #692 (Div. 2, based on Technocup 2021 Elimination Round 3)

Codeforces Round #692 (Div. 2, based on Technocup 2021 Elimination Round 3)

從傳智杯到牛客到cf, 一條龍, 腦子有點呆

A - In-game Chat

int main() {
    IOS;
    for (cin >> _; _; --_) {
        cin >> n >>  s + 1;
        int c = 0;
        per (i, n, 1) if (s[i] == ')') ++c; else break;
        cout << (c * 2 > n ? "YES\n" : "NO\n");
    }
    return 0;
}

B - Fair Numbers

1~9的公倍數為2520, 故最多檢測2519個數, 就能找到最小的公平數

bool check(ll x) {
    ll y = x;
    while (x) {
        if (x % 10 == 0) { x /= 10; continue; }
        if (y % (x % 10)) return 0;
        x /= 10;
    }
    return 1;
}
 
int main() {
    IOS;
    for (cin >> _; _; --_) {
        ll n; cin >> n;
        for (ll i = n; i <= 1e18; ++i) 
            if (check(i)) { cout << i << '\n'; break; }
    }
    return 0;
}

C - Peaceful Rooks

按理來說每個數(不在對角線上的)移動一次剛剛好

但是他要就不能相互攻擊, 有的就要先讓出個位置了, 比如 (2, 3), (3, 4) (4, 2)

成了個環, 要先有個點到其他位置呆著所以總步數 +1

就用並查集判有多少個環就行了

int find(int x) { return x == f[x] ? x : f[x] = find(f[x]); }
 
int main() {
    IOS;
    for (cin >> _; _; --_) {
        cin >> n >> m;
        rep (i, 1, n) f[i] = i;
        ll ans = 0;
        rep (i, 1, m) {
            int x, y; cin >> x >> y;
            if (x == y) continue; ++ans;
            x = find(x), y = find(y);
            if (x == y) ++ans;
            else f[y] = x;
        }
        cout << ans << '\n';
    }
    return 0;
}

D - Grime Zoo

當?序列為 111..000 or 000...111 or 00..00 or 11..11 時最小

不存在 01, 10相間, 這個證明有點費事, 就整個不能 0101的把 不能 11000011000的自己證吧

對於 ..?..?.?.?.. 問號(這四個問號在是相鄰的)對應 0101, 記 st[i][0, 1, 2] 表示從1~i中有多少個 0, 1, ?, ed[i][0,1,2] 同理

0101 下標分別為 a, b, c, d 且 a < b < c < d, 序列總長為n

對於b和c貢獻為 st[b][0] * x + ed[b][0] * y + st[c][1] * y + ed[c][1] * x

將序列變為 0001 bc的貢獻為: (st[b][1] - 1(b變成0了-1)) * x + (ed[b][1] - 1) * y + (st[c][1] - 1) * y + (ed[c][1] - 1) * x

不論變成 0001 還是 0111 都比 0101 要小, 當然肉眼也可見,

想想也因該發現 00000, 1111最小畢竟為0, 但是我們能改的位置有限, 記我們只能改 問號為 1 or 0

拋棄不能改的位置也理應是 00000, 1111是最小, 但還要考慮 不能改的位置那隻好妥協成了 00001111.. or 11111000.. or 00000.. or 111..

int main() {
    IOS; ll x, y; cin >> s >> x >> y;
    rep (i, 1, s.size()) rep (j, 0, 2)
        st[i][j] = st[i - 1][j] + (j < 2 ? s[i - 1] == '0' + j : s[i - 1] == '?');
    per (i, s.size(), 1) rep (j, 0, 2)
        ed[i][j] = ed[i + 1][j] + (j < 2 ? s[i - 1] == '0' + j : s[i - 1] == '?');
    int cnt0 = 0, cnt1 = 0;
    ll t = 0, res, ans;
    rep (i, 1, s.size())
        if (s[i - 1] == '0') ++cnt0, t += cnt1 * y;
        else ++cnt1, t += cnt0 * x;
    res = ans = t;
    rep (i, 1, s.size()) if (s[i - 1] == '?') {
        res -= (st[i - 1][0] + st[i - 1][2]) * x + ed[i + 1][0] * y;
        res += st[i - 1][1] * y + (ed[i + 1][1] + ed[i + 1][2]) * x;
        umin(ans, res);
    } res = t;
    per (i, s.size(), 1) if (s[i - 1] == '?') {
        res -= st[i - 1][0] * x + (ed[i + 1][0] + ed[i + 1][2]) * y;
        res += (st[i - 1][1] + st[i - 1][2]) * y + ed[i + 1][1] * x;
        umin(ans, res);
    }
    cout << ans;
    return 0;
}