P6047-丝之割【斜率优化,dp】
前言
然而丝之鸽还是没有出
正题
题目链接:https://www.luogu.com.cn/problem/P6047
题目大意
两个平行的线,上面连接着若干条弦,第iii条连接上方的xix_ixi个下方的yiy_iyi。
然后每次可以选择一个位置(i,j)(i,j)(i,j),可以切断任何位于位置(u,v)(u,v)(u,v)的弦仅当满足条件(u>i,v<j)(u>i,v<j)(u>i,v<j),消耗代价为ai∗bja_i*b_jai∗bj。
求切断所有线的最小代价。
解题思路
如果我们将下面那条线翻转过来,我们就有条件(u>i,v>j)(u>i,v>j)(u>i,v>j),我们将弦看成坐标的话,我们可以发现其实就是每次选择一个点然后将右下角的点都去掉。
所以就有以下优化
做完以下优化后,对于弦我们可以求到xxx递增,yyy递减的序列。转换到之后就是axa_xax递减,byb_yby递增的序列,可以进行dpdpdp。
fi=min{fj,fj+axj+1byi}f_i=min\{f_j,f_j+a_{x_j+1}b_{y_i}\}fi=min{fj,fj+axj+1byi}
考虑斜率优化
fi=fj+axj+1byif_i=f_j+a_{x_j+1}b_{y_i}fi=fj+axj+1byi
转换成函数
fj=−axj+1byi+fif_j=-a_{x_j+1}b_{y_i}+f_ifj=−axj+1byi+fi
斜率为−byi-b_{y_i}−byi要求截距最小,维护下凸壳(斜率递增)。
然后因为都是单调的,可以用单调队列维护。
codecodecode
#include<cstdio> #include<algorithm> #define ll long long using namespace std; const ll N=3e5+10; struct node{ll x,y; }a[N]; ll n,m,q[N]; double x[N],y[N],f[N]; bool cmp(node x,node y) {return (x.x==y.x)?(x.y<y.y):(x.x<y.x);} double slope(ll i,ll j){if(a[i+1].x==a[j+1].x)return 1e18;return (f[i]-f[j])/(a[j+1].x-a[i+1].x); } int main() {scanf("%lld%lld",&n,&m);for(ll i=1;i<=n;i++)scanf("%lf",&x[i]);for(ll i=n;i>=1;i--)scanf("%lf",&y[i]);x[0]=y[0]=1e18;for(ll i=1;i<=n;i++)x[i]=min(x[i],x[i-1]),y[i]=min(y[i],y[i-1]);for(ll i=1;i<=m;i++)scanf("%lld%lld",&a[i].x,&a[i].y),a[i].y=n-a[i].y+1;sort(a+1,a+1+m,cmp);ll p=0;a[0].y=2147483647/3;for(ll i=1;i<=m;i++)if(a[i].y<a[p].y)a[++p]=a[i];m=p;ll l=1,r=1;for(ll i=1;i<=m;i++)a[i].x=x[a[i].x-1],a[i].y=y[a[i].y-1];for(ll i=1;i<=m;i++){while(l<r&&slope(q[l],q[l+1])<=a[i].y)l++;ll pos=q[l];f[i]=f[pos]+a[pos+1].x*a[i].y;while(l<r&&slope(q[r-1],q[r])>slope(q[r],i))r--;q[++r]=i;}printf("%.0lf",f[m]); }总结
以上是生活随笔为你收集整理的P6047-丝之割【斜率优化,dp】的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 根号怎么打出来 2个方法带你了解
- 下一篇: P4593-[TJOI2018]教科书般