1. 程式人生 > 實用技巧 >Educational Codeforces Round 97 (Rated for Div. 2)

Educational Codeforces Round 97 (Rated for Div. 2)

A

在 l ~ r 之間肯定不行

當 a > r, 則 l >= a/2 即 r < a <= 2l, 即 r < 2l

當 a < l, 則 r / (a/2) - (l-1) / (a/2) ≡ 0, 即 r - l + 1 < a / 2 即 2r - 2l + 2 < a < l

即 2r - 2l + 2 + 1 < l 與 l < r 相悖不存在 a < l

int main() {
    IOS;
    for (cin >> _; _; --_) {
        ll a, b; cin >> a >> b;
        if (a * 2 > b) cout << "YES\n";
        else cout << "NO\n";
    } 
    return 0;
}

B

每次操作 消除一個 00 或 11

int main() {
    IOS;
    for (cin >> _; _; --_) {
        cin >> n; cin >> s + 1;
        int ans = 0, cur = 0;
        rep (i, 2, n) 
            if (s[i] == s[i - 1]) ++ans;
        cout << (ans + 1) / 2 << '\n';
    } 
    return 0;
}

C

01揹包

dp, 揹包容量為 2n (即所有物品從 n 開始放 放到 2n - 1), 你不會把 n 個物品瘋狂往後放吧, 肯定不是最小值

int main() {
    IOS;
    for (cin >> _; _; --_) {
        cin >> n;
        rep(i, 1, n) cin >> a[i];
        sort(a + 1, a + 1 + n);
        rep(j, 1, n) f[j] = 1e15;
        rep(i, 1, n << 1)
            per(j, min(n, i), 1) 
                umin(f[j], f[j - 1] + abs(i - a[j]));
        cout << f[n] << '\n';
    }
    return 0;
}

D

我是sb, 我是sb, 我是sb

腦子沒轉過來彎

連續遞增的一段可以作為 兄弟節點

其之後的每個連續段(即兄弟節點), 可以依次放在 前一段遞增序列 的下面, 作為其子節點

(就是這裡,我卡住了, 為啥能依次放啊? 我一直卡在只能放在 前一段遞增序列 的最後一個節點上, 怎麼著都轉不過來彎)

我是sb, 我是sb, 我是sb

int main() {
    IOS; a[1] = 1; 
    for (cin >> _; _; --_) {
        cin >> n >> m;
        rep (i, 2, n) {
            cin >> a[i];
            if (a[i] < a[i - 1]) ++m;
            h[i] = h[m] + 1;
        }
        cout << h[n] << '\n';
    }
    return 0;
}

G

為啥不敢去看G啊, 原來難度不一定遞增啊

這tm就是一道 AC自動機裸體, 改一點點就行, 可以看看我置頂的 字串 板子

這就是套板子完事, 思維也沒考, 就考個資料結構, 這也能放在G....

struct AC {
    static const int N = 3e5 + 5, M = 26, C = 'a'; //字串總長度, 字元範圍
 
    int trie[N][M], cnt[N], fail[N], vis[N], tot;
    vector<multiset<int>> idx; //記錄節點結尾的字串id
    int q[N], idn[N], mx[N];
 
    void init() {
        idx.resize(1, multiset<int>());
    }
 
    int newnode() {
        idx.pb(multiset<int>());
        mx[++tot] = -1;
        return tot;
    }
 
    void insert(char* s, int id) {
        int p = 0;
        for (int i = 0; s[i]; ++i) {
            int ch = s[i] - C;
            if (!trie[p][ch]) trie[p][ch] = newnode();
            p = trie[p][ch];
        }
        ++cnt[p]; idn[id] = p;
        idx[p].insert(0);
        mx[p] = 0;
    }
 
    void build() {
        int head = 0, tail = -1;
        rep(i, 0, M - 1) if (trie[0][i]) q[++tail] = trie[0][i];
        while (head <= tail) {
            int p = q[head++];
            rep(i, 0, M - 1)
                if (trie[p][i])
                    fail[trie[p][i]] = trie[fail[p]][i], q[++tail] = trie[p][i];
                else trie[p][i] = trie[fail[p]][i];
        }
    }
 
    int query(char* s) {
        set<int> v;
        int p = 0, res = -1;
        for (int i = 0; s[i]; ++i) {
            p = trie[p][s[i] - C];
            for (int tmp = p; tmp && !v.count(tmp); tmp = fail[tmp]) {
                umax(res, mx[tmp]); v.insert(tmp);
            }
        }
        return res;
    }
 
    void change(int id, int k, int yk) {
        int p = idn[id];
        idx[p].erase(idx[p].find(yk)); idx[p].insert(k);
        mx[p] = *idx[p].rbegin();
    }
} ac;
 
const int N = 3e5 + 5;
 
int n, m;
int a[N];
char s[N];
 
int main() {
    IOS; cin >> n >> m; ac.init();
    rep(i, 1, n) cin >> s, ac.insert(s, i);
    ac.build();
    rep(i, 1, m) {
        int op; cin >> op;
        if (op == 2) {
            cin >> s;
            cout << ac.query(s) << '\n';
        }
        else {
            int k, s; cin >> k >> s;
            ac.change(k, s, a[k]); a[k] = s;
        }
    }
    return 0;
}