E. Chain Reaction

_Yxc發表於2024-04-26

https://codeforces.com/contest/1954/problem/E

題意:n個數,可以對每個數釋放閃電,閃電從釋放的位置一直傳到左右邊界或者傳到某個小於等於0的數終止,並且每個數都會減去閃電值k。問最少多少次釋放閃電後可以讓所有的數小於等於0。

思路:從左往右考慮,假設第一個數的權值為1,如果當前數>前一個數,那麼權值+1。如果前一個數小於當前數,前一個數的權值-1。最後求出來每個強度的數一個權值。(i - k + 1) / k * weight[i],就是所有數值為i的數變成0需要電機的次數。 可以求一個字首和分塊計算,降低時間複雜度。

總結:沒寫過這種題型,感覺比較難理解,最後還有個類似分塊的思想。分塊:給個左端點,可以知道右端點,在這個左右端點的區間內,所有數的計算方式都一樣,可以把他們按同樣的方式處理,避免了一個一個處理,降低計算次數。

void solve(){
    int n;
    cin >> n;

    vector<int> a(n);
    for (auto& x : a){
        cin >> x;
    }

    int m = *max_element(a.begin(), a.end());
    vector<int> b(m + 1);
    b[a[0]] ++;
    for (int i = 1; i < n; ++i){
        if (a[i] > a[i - 1]){
            b[a[i]] ++;
        }
        if (a[i - 1] < a[i]){
            b[a[i - 1]] --;
        }
    }

    for (int i = 1; i <= m; ++i){
        b[i] += b[i - 1];
    }


    for (int k = 1; k <= m; ++k){
        long long ans = 0;
        for (int i = 1; i <= m; i += k){
            ans += 1ll * (i + k - 1) / k * (b[min(i + k - 1, m)] - b[i - 1]);
        }
        cout << ans << " \n"[k == m];
    }
}

相關文章