AtCoder-abc228_h Histogram题解

题目链接

题目大意

给定一段长度为\(n\)的数组\(a\)\(c\),表示\(i\)的大小和将 \(a_i+1\) 的费用。如果最后剩\(k\)个不同的\(a_i\)就将费用加上 \(X\times k\)

题目分析

首先该题想让我们的最后剩下的 \(a_i\) 个数最少,那我们就没必要创造新的 \(a_i\) 。所以最后的\(a_i\)序列一定是

\[a_{b_1},a_{b_1}···a_{b_1}|a_{b_2},a_{b_2}···a_{b_2}|a_{b_m},a_{b_m}···a_{b_m} \]

即一段连续的\(a_i\)
假设\(dp_i\)为以\(i\)为结尾的最小代价
先将\(a\)数组和\(c\)数组按\(a_i\)大小排序。建个结构体或\(\mathrm{pair}\)就行。这样后面就不用绝对值了。

\[dp_i \min \limits_{j=1}^{i}=\left(dp_{j-1}+\sum_{k=1}^{j}c_k(a_i-a_k)+X \right) \]

\((a_i-a_k)\)这一项不好处理,所以把\(\sum\)拆开。

\[dp_i \min \limits_{j=1}^{i}=\left(dp_{j-1}+\sum_{k=1}^{j}c_k\times a_i-\sum_{k=1}^{j}c_k\times a_k+X \right) \]

然后把\(\sum\)用前缀和替代。

\(s1_i=\sum\limits_{j=1}^{i}c_j\)

\(s2_i=\sum\limits_{j=1}^{i}c_j\times a_j\)

\[dp_i \min \limits_{j=1}^{i}=\left(dp_{j-1}+a_i\times\left(s1_i-s1_{j-1}\right)-(s2_i-s2_{j-1})+X \right) \]

然后这个式子看起来就很斜率优化。式子左边化简

\[dp_{j-1}+a_is1_i-a_is1_{j-1}-s2_i+s2_{j-1}+X \]

我们考虑两个数\(j_1\)\(j_2\)。当\(j_1\)\(j_2\)更优势,式子为

\[dp_{j1-1}+a_is1_i-a_is1_{j1-1}-s2_i+s2_{j1-1}+X\le dp_{j2}+a_is1_i-a_is1_{j2-1}-s2_i+s2_{j2-1}+X \]

消去不含\(j\)的项

\[dp_{j1-1}-a_is1_{j1-1}+s2_{j1-1}\le dp_{j2-1}-a_is1_{j2-1}+s2_{j2-1} \]

移项

\[dp_{j1-1}-dp_{j2-1}+s2_{j1-1}-s2_{j2-1}\le a_is1_{j1-1}-a_is1_{j2-1} \]

右边都有\(a_i\),合并一下

\[dp_{j1-1}-dp_{j2-1}+s2_{j1-1}-s2_{j2-1}\le a_i\left(s1_{j1-1}-s1_{j2-1}\right) \]

把左边含有\(j\)的除到右边

\[\frac{dp_{j1-1}-dp_{j2-1}+s2_{j1-1}-s2_{j2-1}}{s1_{j1-1}-s1_{j2-1}}\le a_i \]

然后调整一下

\[\frac{\left(dp_{j1-1}+s2_{j1-1}\right)-\left(dp_{j2-1}+s2_{j2-1}\right)}{s1_{j1-1}-s1_{j2-1}}\le a_i \]

这样就行了。\(Y\)就是\(dp_{j-1}+s2_{j-1}\),\(X\)就是\(s1_{j-1}\)

然后就完事了

代码

#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
#define int long long
typedef long double lb;
int n,xx;
const int N=2e5+10;
struct node{
    int a,c;
}a[N];
bool cmp(node x,node y)
{
    return x.a<y.a;
}
int q[N],dp[N],s1[N],s2[N];
lb X(int a)
{
    return s1[a-1];
}
lb Y(int a)
{
    return dp[a-1]+s2[a-1];
}
lb slope(int a,int b)
{
    return (Y(a)-Y(b))/(X(a)-X(b));
} 
int ans(int x,int y)
{
    return dp[y-1]+a[x].a*(s1[x]-s1[y-1])-(s2[x]-s2[y-1])+xx;
}
signed main()
{
    cin>>n>>xx;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i].a>>a[i].c;
    }
    sort(a+1,a+1+n,cmp);
    int h=1,t=0;
    for(int i=1;i<=n;i++)
    {
        s1[i]=s1[i-1]+a[i].c;
        s2[i]=s2[i-1]+a[i].c*a[i].a;
    }
    for(int i=1;i<=n;i++)
    {
        while(h<t&&slope(i,q[t])<slope(q[t],q[t-1]))t--;
        q[++t]=i;
        while(h<t&&slope(q[h],q[h+1])<a[i].a)h++;
        dp[i]=ans(i,q[h]);
    }
    cout<<dp[n];
}
posted @ 2025-10-18 10:51  NumLuck  阅读(13)  评论(0)    收藏  举报