Loading

不条理狂诗曲

给出两个做法,一个平凡,一个大牛逼。

Sol1 分治

很常规吧,不说了。

Sol2 线性做法

考虑 \(f\) 为随便选不选 \(i\) 的方案,\(g\) 为一定不选 \(i\) 的方案。
转移:

\[f' \leftarrow \max(f, g + a_i), g' \leftarrow f \]

很难搞,把前面的式子变下型:

\[f' \leftarrow f + \max(0, a_i - (f - g)), g' \leftarrow f \]

发现了什么?
\(f \rightarrow f'\) 的变化值和 \(f' - g'\) 均为 \(\max(0, a_i - (f - g))\)!!!
那这个性质就很优美了啊,从左往右扫,记 \(r_x\) 为右端点为 \(x\)\(f(l, r)\) 之和,考虑 \(r_{x - 1} \rightarrow r_x\) 的变化值 \(\Delta_x\),显然 \(\Delta_x = -\Delta_{x - 1} + xa_x\),如果不考虑和 \(0\)\(\max\) 直接扫一遍就没了。
如果考虑,那么我们维护一个二元组组成的集合 \(S\),里面的每个二元组 \((x, y)\)\(x\) 表示一个 \(f - g\), \(y\) 表示 \(f - g = x\)\(f - g\) 有多少个。
显然 \(f - g\) 类似一次函数的复合,仍然是一次函数,可以对斜率和截距打一个全局 tag(这里斜率只能是 \(\{-1, 1\}\))。于是 \(S\) 在维护的过程中始终有序,证明就是归纳。
然后又有性质了,暴力将 \(S\) 中的负数删掉是对的,因为每次这么做都会减少一个元素,而最多插入 \(\mathcal{O}(n)\) 个元素,且 \(S\) 在维护过程中又是有序的,只需要考虑队头和队尾即可!!!

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
// typedef __int128 i128;
typedef pair<int, int> pii;
const int N = 2e5 + 10, mod = 1e9 + 7;
template<typename T>
void dbg(const T &t) { cout << t << endl; }
template<typename Type, typename... Types>
void dbg(const Type& arg, const Types&... args) {
    cout << arg << ' ';
    dbg(args...);
}
namespace Loop1st {
int n;
ll a[N], tx = 1, ty, sum, res, ans;
deque<pair<ll, int>>S; // 每次 decode 后 S 要么升序要么降序
ll decode(ll x) { return tx * x + ty; }
ll encode(ll x) { return (x - ty) / tx; } // * tx <=> / tx(tx \in {-1, 1}) 
void main() {
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    for (int i = 1; i <= n; i++) {
        if (S.empty() || encode(0) <= S.front().first) S.push_front({encode(0), 1});
        else S.push_back({encode(0), 1}); // 这里是插入 f' - g'
        tx = -tx; ty = -ty + a[i]; sum = (mod - sum + a[i] * i) % mod;
        int cnt = 0;
        while (!S.empty() && decode(S.front().first) < 0) {
            sum = (sum + mod - decode(S.front().first) * S.front().second % mod) % mod;
            cnt += S.front().second;
            S.pop_front();
        }
        while (!S.empty() && decode(S.back().first) < 0) {
            sum = (sum + mod - decode(S.back().first) * S.back().second % mod) % mod;
            cnt += S.back().second;
            S.pop_back();
        }
        // if (cnt) {
            if (S.empty() || encode(0) <= S.front().first) S.push_front({encode(0), cnt});
            else S.push_back({encode(0), cnt});
        // }
        res = (res + sum) % mod;
        ans = (ans + res) % mod;
    }
    cout << ans << '\n';
}

}
int main() {
    // freopen("data.in", "r", stdin);
    // freopen("data.out", "w", stdout);
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int T = 1;
    // cin >> T;
    while (T--) Loop1st::main();
    return 0;
}
posted @ 2025-12-18 18:13  循环一号  阅读(30)  评论(0)    收藏  举报