首页 > 其他分享 >【题解】LOJ #6384. 「是男人就过8题——Pony.ai」SignLocation

【题解】LOJ #6384. 「是男人就过8题——Pony.ai」SignLocation

时间:2022-12-30 07:22:05浏览次数:68  
标签:SignLocation ll Pony limits int 题解 s1 s2 sum

题意

LOJ #6384. 「是男人就过8题——Pony.ai」SignLocation

给定 \(n\) 个整点 \(p_1, ..., p_n\) 以及 \(k\) 次标记点的机会,定义 \(c(i, j)\) 为:

  1. 第 \(i\) 个整点和第 \(j\) 个整点之间存在标记点,则 \(c(i, j)\) 为距离 \(i\) 最近的标记点与 \(i\) 的坐标之差。

  2. 反之为 \(|p_i - p_j|\)

注意标记点不一定在整点上。

求 \(\sum\limits_{i \neq j} c(i, j)\) 的最小值。

\(0 \leq k \leq 200, 1 \leq n \leq 10000, p_i \leq 10^7\)

思路

决策单调性优化 dp.

首先可以用反证法证明标记整点最优。

于是可以考虑设 \(f[i][j]\) 表示已经标记 \(i\) 个整点,最后一个标记的是第 \(j\) 个整点时已经产生的最小贡献。

容易发现选出的 \(k\) 个标记点会将值域分成 \(k + 1\) 个区间(可能为空),不妨令 \(\sum\limits_{i \neq j} c(i, j)\) 算作是 \(i\) 所在区间的贡献。

假设当前最后一个标记点在 \(r\),倒数第二个标记点在 \(l\),那么转移时只需要考虑区间 \((l, r)\) 的贡献。

分类讨论推一下式子:

  1. \(l < j < r\)
    此时 \((i, j)\) 之间没有其他的标记点,于是贡献为坐标之差。
    \(\sum\limits_{i \neq j} c(i, j) = 2 \sum\limits_{p = l + 2}^{r - 1} \sum\limits_{q = l + 1}^{r - 1} (x_p - x_q)\)
    考察每一个下标的出现次数,可以化简上式得:
    \(原式 = \sum\limits_{p = l + 2}^{r - 1} x_p (p - l - 1) - \sum\limits_{q = l + 1}^{r - 2} x_q (r - q - 1)\)

  2. \(j \leq l\)
    此时距离 \(i\) 最近的标记点为 \(l\)
    \(\sum\limits_{i \neq j} c(i, j) = \sum\limits_{p = l + 1}^{r - 1} (x_p - x_l)l\)
    同理化简得 \(原式 = (\sum\limits_{p = l + 1}^{r - 1} x_p l) - x_l (r - l - 1) l\)

  3. \(j \geq r\)
    此时距离 \(i\) 最近的标记点为 \(r\)
    \(\sum\limits_{i \neq j} c(i, j) = \sum\limits_{p = l + 1}^{r - 1} (x_r - x_p)(n - r + 1)\)
    化简得 \(原式 = x_r (r - l - 1) (n - r + 1) - \sum\limits_{p = l + 1}^{r - 1} x_p(n - r + 1)\)

发现只需处理 \(p_i\) 和 \(i p_i\) 的前缀和就可以 \(O(1)\) 计算一段区间的贡献。

观察做法,发现是一个划分区间的 dp(选点等价于划分区间),于是联想到决策单调性优化 dp.

根据题解知 确实有决策单调性(具体不太会证),于是上单调性分治优化即可,时间复杂度 \(O(k n \log n)\)

代码

#include <cstdio>
#include <algorithm>
using namespace std;

typedef long long ll;

const int maxn = 1e4 + 5;
const int maxk = 2e2 + 5;
const ll inf = 1e18;

int n, k;
int p[maxn];
ll s1[maxn], s2[maxn];
ll f[maxk][maxn];

ll get1(int l, int r)
{
    ll ans = 2 * (s2[r - 1] - s2[l + 1] + s2[r - 2] - s2[l] - (s1[r - 1] - s1[l + 1]) * (l + 1) - (s1[r - 2] - s1[l]) * (r - 1));
    ans += 1ll * l * (s1[r - 1] - s1[l] - 1ll * p[l] * (r - l - 1));
    ans += 1ll * (n - r + 1) * (1ll * p[r] * (r - l - 1) - s1[r - 1] + s1[l]);
    return ans;
}

ll get2(int l, int r)
{
    if (l == r) return 0;
    ll ans = 2ll * (s2[r] - s2[l + 1] + s2[r - 1] - s2[l] - (s1[r] - s1[l + 1]) * (l + 1) - (s1[r - 1] - s1[l]) * r);
    ans += 1ll * l * (s1[r] - s1[l] - 1ll * p[l] * (r - l));
    return ans;
}

void solve(int cur, int l, int r, int vl, int vr)
{
    if (l > r) return;
    int mid = (l + r) >> 1, pos = l;
    ll res = inf;
    for (int i = min(vr, mid - 1); i >= vl; i--)
    {
        ll cost = f[cur - 1][i] + get1(i, mid);
        if (cost < res) res = cost, pos = i;
    }
    f[cur][mid] = res;
    solve(cur, l, mid - 1, vl, pos);
    solve(cur, mid + 1, r, pos, vr);
}

int main()
{
    while (~scanf("%d%d", &n, &k))
    {
        k = min(k, n);
        for (int i = 1; i <= n; i++)
        {
            scanf("%d", &p[i]);
            s1[i] = s1[i - 1] + p[i];
            s2[i] = s2[i - 1] + 1ll * p[i] * i;
        }
        if (k == 0)
        {
            ll ans = 0;
            for (int i = 1; i <= n; i++) ans += (1ll * p[i] * i - s1[i]);
            printf("%lld\n", (ans << 1ll));
            continue;
        }
        for (int i = 1; i <= k; i++)
        {
            if (i == 1) solve(1, 1, n, 0, 0);
            else solve(i, i, n, i - 1, n - 1);
        }
        ll ans = inf;
        for (int i = k; i <= n; i++) ans = min(ans, f[k][i] + get2(i, n));
        printf("%lld\n", ans);
    }
    return 0;
}

标签:SignLocation,ll,Pony,limits,int,题解,s1,s2,sum
From: https://www.cnblogs.com/lingspace/p/loj-6384.html

相关文章

  • Codeforces 1336 F Journey 题解
    题目链接这题的方法口糊一下没有很难,没达到3500的水准。但是写起来才发现是真的恶心(主要是容易写错),没写过这么累的题,可能难度就体现在这里吧。计数的时候是要分类讨论......
  • Codeforces 1336 F Journey 题解
    题目链接这题的方法口糊一下没有很难,没达到3500的水准。但是写起来才发现是真的恶心(主要是容易写错),没写过这么累的题,可能难度就体现在这里吧。计数的时候是要分类讨论......
  • CF1765H题解
    思路:对每个病人单独来考虑。我们发现正着来考虑每个位置放哪个病人不能保证对之后的病人无影响,故尝试着反着做,当前处理到第\(i\)个位置时,第\(t\)个还没有被放置的病人......
  • [NOIP2013 提高组] 货车运输 题解
    [NOIP2013提高组]货车运输题解本题解介绍一种最大生成树+并查集+启发式合并离线的做法。想法题目要多次求两点之间的最大瓶颈路长度,所以可以先参照最小瓶颈路的通......
  • LeetCode 寻找数组的中心下标算法题解 All In One
    LeetCode寻找数组的中心下标算法题解AllInOne724.FindPivotIndex寻找数组的中心下标"usestrict";/****@authorxgqfrms*@licenseMIT*@copyr......
  • Cordforces 1774D题解
    题目链接:https://codeforces.com/problemset/problem/1774/DDescription:给定n个长为m的二进制串,每次可以选出任意两个,然后交换这两个二进制串同一列的数。求最少的操作......
  • [题解] CF1761E Make It Connected
    CF1761EMakeItConnected题目大意给一张无向图,每次操作表现为选择一个点\(x\),断开所有原来连上的边,连接所有原来断开的边。求最少需要几步使得图联通,并构造方案。思......
  • LOJ 6041 「雅礼集训 2017 Day7」事情的相似度 题解 (SAM+启发式合并)
    题目链接首先很容易想到的是对反串求SA和LCP,然后询问就是求起点在某个区间内的所有后缀两两LCP的最大值,可以用莫队解决,时间复杂度\(O(n\sqrtnlogn)\),应该是过不了的。......
  • P5137 题解
    前言首先感谢所有帮助我卡常的大佬们。题意求\((\sum_{i=0}^{n}a^ib^{n-i})\modp\)的值(\(n\leq10^{18}\),\(p\)不一定为质数)。分析看到数据范围,首先想到快......
  • C#提示指定的路径或文件名太长问题解决办法
    我用的是.net4.0的环境,直接在app.config配置文件中加几行配置就行。如下图:<configuration><runtime><AppContextSwitchOverridesvalue="Switch.System.IO.......