欢迎访问 生活随笔!

生活随笔

当前位置: 首页 >

P6047-丝之割【斜率优化,dp】

发布时间:2023/12/3 51 豆豆
生活随笔 收集整理的这篇文章主要介绍了 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_jaibj

求切断所有线的最小代价。


解题思路

如果我们将下面那条线翻转过来,我们就有条件(u>i,v>j)(u>i,v>j)(u>i,v>j),我们将弦看成坐标的话,我们可以发现其实就是每次选择一个点然后将右下角的点都去掉。

所以就有以下优化

  • 如果一个弦代表的点在其他弦代表点的右下角,那么该点不影响结果。可以去掉
  • 如果一个点的代价比他右上角的其中一个点的代价高,那么必定选那个点更优。所以我们可以对于aaabbb都取一个前缀minminmin
  • 做完以下优化后,对于弦我们可以求到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】的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。