E. Chain Reaction

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];
    }
}
posted @ 2024-04-26 09:29  _Yxc  阅读(18)  评论(0编辑  收藏  举报