• [题解] LuoguP4983 忘情


    https://www.luogu.com.cn/problem/P4983

    首先对柿子化简过后长这样

    [(1+sum x)^2 ]

    考虑一个naive的DP,(f_{i,j})表示前(i)个数分成(j)段的最小值,然后不难用斜率优化将其优化到(O(nm))

    根据直觉这玩意儿显然有凸性

    考虑wqs二分,同样的在dp时斜率优化即可,复杂度(O(n log V))

    但如果你二分的是整数的话可能需要注意一些细节,如果当二分切线斜率后切到了凸包的一条边上要优先取横坐标较小的那个点,不然可能找不到合法点。(如果是下面代码中那种二分的话)

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef double db;
    
    const int N = 1e5 + 10;
    ll a[N], s[N], dp[N];
    int n, m;
    
    inline db X(int i) { return s[i] - 1; }
    inline db Y(int i) { return dp[i] + (s[i] - 1) * (s[i] - 1); }
    inline db slope(int i, int j) {
        return (Y(j) - Y(i)) / (X(j) - X(i));
    }
    
    int calc(ll mid) {
        static int cnt[N], q[N];
        dp[0] = cnt[0] = 0;
        int *ql = q + 1, *qr = q;
        *++qr = 0;
        for (int i = 1; i <= n; ++i) {
            while (ql < qr && 2.0 * s[i] > slope(*ql, *(ql + 1))) ++ql;
            int j = *ql;
            dp[i] = dp[j] + (s[i] - s[j] + 1) * (s[i] - s[j] + 1) - mid;
            cnt[i] = cnt[j] + 1;
            while (ql < qr && slope(*(qr - 1), *qr) > slope(*(qr - 1), i)) --qr;
            *++qr = i;
        }
        return cnt[n];
    }
    
    int main() {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; ++i) {
            scanf("%lld", &a[i]);
            s[i] = s[i - 1] + a[i];
        }
        ll l = -1e16, r = 0, p = 1;
        while (l <= r) {
            ll mid = (l + r) >> 1;
            if (calc(mid) <= m) l = mid + 1, p = mid;
            else r = mid - 1;
        }
        calc(p);
        printf("%lld
    ", dp[n] + p * m);
        return  0;
    }
    
  • 相关阅读:
    转载Dockerfile 中 RUN, CMD, ENTRYPOINT 的区别
    在linux上通过ssh使用github
    dns服务
    centos6 free 和 centos 7的free 的差异与对比
    无重复字符的最长子串
    go get命令在go mod目录下与正常目录执行的区别
    安装git
    转载 筛子算法之golang实现求素数解析
    Go语言基础之并发
    go之无缓冲channel(通道)和有缓冲channel(通道)
  • 原文地址:https://www.cnblogs.com/wxq1229/p/13441840.html
Copyright © 2020-2023  润新知