abc407 F 题题解

abc407 F 题题解

这是另一个正解的代码,有需要的话,请自行食用。

here

前言

这个做法理论上可以卡到 \(O(N^2)\),但是我们充分利用 \(AtCoder\)脚造数据,愉快的以近似线性的时间复杂度通过本题。

做法

首先,我们肯定不能直接暴力去算,这样是严格 \(O(N^2)\) 的,肯定过不了。

那么我们考虑拆贡献。

考虑单独去算每一个元素的贡献。

考虑一个元素在什么情况下会有贡献。

显然是在这个元素是一个区间内的最大值的时候算贡献。

怎么算一个元素的最大伸展长度?

可以通过正反两个单调栈解决。

如果不会单调栈的话,请自行解决。

说到这里,考虑怎么去算。

肯定这个大区间内部的每一个小区间最大值都是这个值。

但是直接去枚举的话,总时间复杂度 \(O(n^3)\),爆炸。

那么直接枚举左端点,右端点在 \([i,r]\) 范围内肯定都行。

那么这么枚举还是 \(O(N^2)\) 的,显然会死。

所以有一个小小的优化,能直接干爆脚造数据。

就是看左边和右边哪个元素更少。

虽然这个很容易卡爆,但是还是因为数据太烂,他就活了下来,得到了和线性一样的时间复杂度。

然后呢?

我们可以通过差分数组维护这个 \(k\) 为多少的时候的答案,到最后前缀和一下,然后输出就行了。

具体看代码吧。

代码

#include <bits/stdc++.h>

#define int long long 

using namespace std;

const int N = 2e5 + 10;

int n;
int a[N];
int c[N];
int lef[N];
int rig[N];

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n;
    for (int i = 1;i <= n;++i) {
        cin >> a[i];
    }
    stack<int> st;
    for (int i = 1;i <= n;++i) {
        while (!st.empty() && a[st.top()] <= a[i]) st.pop();
        if (st.empty()) lef[i] = 1;
        else lef[i] = st.top() + 1;
        st.push(i);
    }
    st = stack<int>();
    for (int i = n;i >= 1;--i) {
        while (!st.empty() && a[st.top()] < a[i]) st.pop();
        if (st.empty()) rig[i] = n;
        else rig[i] = st.top() - 1;
        st.push(i);
    }
    for (int i = 1;i <= n;++i) {
        int l = lef[i];
        int r = rig[i];
        //确定左右端点
        if (i - l <= r - i) {
            //如果左边的点的数量<=右边的,枚举左端点
            for (int j = l;j <= i;++j) {
                //枚举区间左端点
                int len1 = i - j + 1;
                int len2 = r - j + 1;
                int mxlen = max(len1, len2);
                int mnlen = min(len1, len2);
                c[mnlen] += a[i];
                c[mxlen + 1] -= a[i];
            }
        }
        else {
            for (int j = i;j <= r;++j) {
                int len1 = j - i + 1;
                int len2 = j - l + 1;
                int mxlen = max(len1, len2);
                int mnlen = min(len1, len2);
                c[mnlen] += a[i];
                c[mxlen + 1] -= a[i];
            }
        }
    }
    for (int i = 1;i <= n;++i) c[i] += c[i - 1];
    for (int i = 1;i <= n;++i) {
        cout << c[i] << '\n';
    }
    cout << "\n";
    return 0;
}
posted @ 2025-05-29 22:59  guoguo160  阅读(19)  评论(0)    收藏  举报