Educational Codeforces Round 170 (Rated for Div. 2) ABCD

lulaalu發表於2024-10-16

來源:Educational Codeforces Round 170 (Rated for Div. 2)

A. Two Screens

題意

給兩個螢幕,兩種操作,每種操作一秒,求讓兩個螢幕顯示兩個指定字串的最短時間

操作:

  1. 在一個螢幕的字串後加任意一個字元
  2. 把一個螢幕的內容複製貼上到另一個螢幕

思路

先弄出相同字首,複製一下,然後不相同的只能用操作1來一個一個加

程式碼

string s1, s2;
int main() {
    IOS;
    int t;
    cin >> t;
    while (t--) {
        cin >> s1 >> s2;
        int same = 0;
        for (int i = 0; i < min(s1.length(), s2.length()); i++) {
            if (s1[i] == s2[i]) same++;
            else break;
        }
        cout << s1.length() + s2.length() - same + (same == 0 ? 0 : 1) << endl;
    }
    return 0;
}

B. Binomial Coefficients, Kind Of

思路

這邊建議,複製貼上給的程式碼,然後列印一下

程式碼

const int MOD = 1e9 + 7;
long long ksm(long long a, long long b, long long MOD) {
    long long res = 1;
    while (b) {
        if (b & 1) res = (res * a) % MOD;
        a = (a * a) % MOD;
        b >>= 1;
    }
    return res;
}
int main() {
    IOS;
    // int C[20][20];
    // for (int n = 0; n < 20; n++) { // loop over n from 0 to N-1 (inclusive)
    //     C[n][0] = 1;
    //     C[n][n] = 1;
    //     for (int k = 1; k < n; k++) // loop over k from 1 to n-1 (inclusive)
    //         C[n][k] = C[n][k - 1] + C[n - 1][k - 1];
    // }
    // for (int n = 0; n < 20; n++) { // loop over n from 0 to N-1 (inclusive)
    //     for (int k = 1; k < n; k++) { cout << C[n][k] << " "; }
    //     cout << endl;
    // }
    int t;
    cin >> t;
    vector<int> n(t), k(t);
    for (int &i : n) cin >> i;
    for (int &i : k) cin >> i;
    for (int i = 0; i < t; i++) {
        cout << ksm(2, k[i], MOD) << endl;
    }
    return 0;
}

C. New Game

題意

一堆數字,第一次選 \(x\),以後只能選 \(x\)\(x+1\)

所選牌中不同的牌不超過 \(k\)

思路

首先想用個 \(cnt\) 陣列存每張牌的數量,用雙指標維護一個視窗,視窗內的都是連續的數字

由於每次擴充視窗的時候要判斷下一個位置和當前位置差值是不是1,我選擇把中間連線的 \(cnt\) 搞成一個負數

遇到負數就重新搞視窗

程式碼

const int N = 4e5 + 10;
int cnt[N];
map<int, int> mp;
void solve() {
    mp.clear();
    int n, k;
    cin >> n >> k;
    for (int i = 0; i < n; i++) {
        int tmp;
        cin >> tmp;
        mp[tmp]++;
    }
    int turn = 0; // 有多少數和間隔
    int pre = 0;
    for (auto [num, c] : mp) {
        if (num != pre && num != pre + 1) {
            cnt[++turn] = -1;
        }
        pre = num;
        cnt[++turn] = c;
    }

    int l = 1, r = 0;
    int now = 0;
    int ans = 0;

    while (r <= turn && l <= turn) {
        while (r - l + 1 < k && now + cnt[r + 1] >= now && r + 1 <= turn) now += cnt[++r];
        ans = max(ans, now);
        if (now + cnt[r + 1] < now || r + 1 > turn) { // 如果是遇到負數
            now = 0;
            l = r + 2;
            r++;
        } else {
            now -= cnt[l++];
        }
    }
    cout << ans << endl;
}

D. Attribute Checks

題意

升級打怪,給一個序列,按順序,遇到0就是升級,但是有兩個屬性

遇到正數和負數分別代表遇到針對兩個屬性的怪了

只有自身的對應屬性大於等於怪才能打敗

問最多打得過多少怪(檢查點)

思路

一眼dp,但是n範圍有點不對勁,先不管

  1. 思路

\(dp[i][j]\) 表示 到目前為止有 \(i\) 分,這 \(i\) 分有 \(j\) 分分配給智力,也就是 \(k=i-j\) 分給體力那麼到第 \(i+1\)\(0\) 之前,最多能過多少檢查點

\(i\) 分加在智力上

\(dp[i][j]=dp[i-1][j-1] + ([i-1,i]區間內小於j的正數數量) + (區間內小於k的|負數|數量)\)

\(i\) 分加在體力上

\(dp[i][j]=dp[i-1][j] + (區間內小於j的正數數量) + (區間內小於k的|負數|數量)\)

比如按如下順序 \(0(i-1),2, -2, -3, 0(i)\)

當碰到2時,需要對 \(dp[i-1][2\dots(i-1)]\)

每次遇到0的時候都要來一遍狀態轉移,這是不會t的,但是每次碰到檢查點要來一次+1這就是 \(O(mn)\)

就硬交,不死心

  1. 最佳化

由於有m分,可以先把兩分之間的那些用一個差分陣列存起來,每次遇到0的時候再操作一下,t不了一點

程式碼

空間也可以最佳化,不過這題都可

在原本的陣列後面補一個0,好處理點

const int N = 2e6 + 10;
const int M = 5005;
int a[N];
int dp[M][M];
signed main() {
    // IOS;
    int n, m;
    cin >> n >> m;
    rep(i, 0, M) fill_n(dp[i], M, 0);
    for (int i = 0; i < n; i++) cin >> a[i];
    a[n] = 0;
    m++;
    n++;
    
    int zero = 0;
    vector<int> dif(m + 5, 0);
    for (int i = 0; i < n; i++) {
        if (a[i] == 0) {
            zero++;
            for (int j = 1; j <= m + 1; j++) dif[j] += dif[j - 1];

            dp[zero][0] = dp[zero - 1][0] + dif[0];
            for (int j = 1; j <= zero; j++) {
                dp[zero][j] = max(dp[zero - 1][j - 1] + dif[j - 1], dp[zero - 1][j] + dif[j]);
            }
            for (int j = 0; j <= m; j++) dif[j] = 0;

        } else if (a[i] > 0) {
            if (a[i] <= zero) {
                dif[a[i]]++;
                dif[zero + 1]--;
            }
        } else if (a[i] < 0) {
            if (-a[i] <= zero) {
                dif[0]++;
                dif[zero + a[i] + 1]--;
            }
        }
    }

    int ans = 0;
    for (int i = 0; i <= zero; i++) {
        ans = max(ans, dp[zero][i]);
    }
    cout << ans;

    return 0;
}

相關文章