AT_abc228_h [ABC228H] Histogram题解
AT_abc228[Histogram]
题解
我们可以发现,操作后的数组中存在的数,原数组中一定存在。所以,一定是在原数组中选定一些“基准数”不动,其余数变为大于它且最近的基准数。我们按照 AAA 数组从小到大排序,这样最优方案一定是把数组分成若干段,每一段都加到段内的最大值。
设 dpidp_{i}dpi 为前 iii 个数产生的最小代价,有转移:
dpi=minj=ij>=1(dpj−1+(∑k=jk<=i(Ai−Ak)∗Ck)+X)dp_{i}=\min_{j=i}^{j>=1}(dp_{j-1}+(\sum_{k=j}^{k<=i}(A_{i}-A{k})*C_{k})+X )dpi=j=iminj>=1(dpj−1+(k=j∑k<=i(Ai−Ak)∗Ck)+X)
把中间的部分拆一下:
∑k=jk<=i(Ai−Ak)∗Ck=Ai∑k=jk<=iCk−∑k=jk<=iAk∗Ck\sum_{k=j}^{k<=i}(A_{i}-A{k})*C_{k}=A_{i}\sum_{k=j}^{k<=i}C_{k}-\sum_{k=j}^{k<=i}A_{k}*C_{k}k=j∑k<=i(Ai−Ak)∗Ck=Aik=j∑k<=iCk−k=j∑k<=iAk∗Ck
用前缀和+斜率优化即可,时间复杂度 O(n)O(n)O(n)。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
struct node
{int a,c;
}a[N];
int n,x;
bool cmp(node x,node y)
{return x.a<y.a;
}
long long dp[N];
long long s1[N],s2[N],X[N],Y[N];
int q[N],l=1,r=0;
double xie(int i,int j)
{return 1.0*(Y[i]-Y[j])/(X[i]-X[j]);
}
int main()
{ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);cin>>n>>x;for(int i=1;i<=n;i++)cin>>a[i].a>>a[i].c;sort(a+1,a+1+n,cmp);memset(dp,127,sizeof(dp));dp[0]=0;for(int i=1;i<=n;i++)s1[i]=s1[i-1]+a[i].c,s2[i]=s2[i-1]+1ll*a[i].a*a[i].c;for(int i=1;i<=n;i++){X[i]=-s1[i-1],Y[i]=dp[i-1]+s2[i-1];while(l<r&&xie(q[r],q[r-1])<=xie(i,q[r]))r--;q[++r]=i;while(l<r&&1ll*(X[q[l]]-X[q[l+1]])*a[i].a>=Y[q[l+1]]-Y[q[l]])l++;dp[i]=1ll*a[i].a*s1[i]+x-s2[i]+1ll*X[q[l]]*a[i].a+Y[q[l]];}cout<<dp[n];return 0;
}