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];
}
}