cf刷題雜記(2)

Aderose_yr發表於2024-09-05

Educational Codeforces Round 167 (Rated for Div. 2)

D. Smithing Skill (D)

很無語的一題······ 運用類似單調佇列思維處理出最優的選擇序列,之後發現 \(c_i\leq 10^9\) 沒法預處理,二分查詢又會被卡成 \(n^2\log n\),唯獨沒想到在 \(a_i\)\(10^6\) 範圍內預處理()不好評價。

bool cmp(xxx n, xxx m) {
    if(n.a - n.b != m.a - m.b) {
        return n.a - n.b < m.a - m.b;
    }
    return n.a < m.a;
}
int main() {
    // ...
    sort(x + 1, x + n + 1, cmp);
    x[0] = ans[0] = {INF, INF + 1};
    for(int i = 1; i <= n; i++) {
        if(x[i].a - x[i].b != x[i - 1].a - x[i - 1].b) {
            if(x[i].a < ans[cnt].a) ans[++cnt] = x[i];
        }
    }
    int cur = cnt;
    for(int i = ans[cnt].a; i < N; i++) {
        if(i >= ans[cur - 1].a) cur--;
        if(!cur) break;
        int num = (i - ans[cur].a) / (ans[cur].a - ans[cur].b) + 1;
        int x = i - num * (ans[cur].a - ans[cur].b);
        dp[i] = num * 2 + dp[x];
    }
    ll sum = 0;
    for(int i = 1; i <= m; i++) {
        scanf("%d", &c[i]);
        if(c[i] < ans[1].a) sum += dp[c[i]];
        else {
            int num = (c[i] - ans[1].a) / (ans[1].a - ans[1].b) + 1;
            int x = c[i] - num * (ans[1].a - ans[1].b);
            sum += dp[x] + num * 2;
        }
    }

E. Distance to Different (E)

不同的 \(a\) 序列可能產生相同的 \(b\) 序列,因此只需要考慮可能的合法 \(b\) 序列;\(a\) 中連續 \(x\) 個相同的數會在 \(b\) 中產生一段長度為 \(x\) 的特定序列,題目即等價於將 \(b\) 劃分成至少 \(k\) 個不同的序列。對於除2以外的所有 \(x\),其產生的序列具有特異性,但 \(x = 2\) 時,若該序列位於 \(b\) 的中部,則 \(b = 1\),與 \(x = 1\) 情況相同,計算時應注意捨去。設 \(dp_{i, j}\) 表示將前 \(i\) 個數劃分成 \(j\) 個序列的方案數,特別地,為節省空間,\(j = k\) 時表示劃分出至少 \(k\) 個序列的方案數。使用字首和最佳化轉移,複雜度 \(O(nk)\).

    dp[0][0] = 1;
    sum[0] = 1; // 初始化
    for(int i = 1; i <= n; i++) {
        for(int j = 0; j <= k; j++) {
            dp[i][min(j + 1, k)] += sum[j];
            if(i > 2 && i < n) {
                dp[i][min(j + 1, k)] += (mo - dp[i - 2][j]);
            }
            dp[i][min(j + 1, k)] %= mo;
        }
        for(int j = 1; j <= k; j++) {
            sum[j] += dp[i][j];
            sum[j] %= mo;
        }
    }