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),我們將弦看成坐標的話,我們可以發(fā)現(xiàn)其實就是每次選擇一個點然后將右下角的點都去掉。
所以就有以下優(yōu)化
做完以下優(yōu)化后,對于弦我們可以求到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?+1?byi??}
考慮斜率優(yōu)化
fi=fj+axj+1byif_i=f_j+a_{x_j+1}b_{y_i}fi?=fj?+axj?+1?byi??
轉換成函數(shù)
fj=?axj+1byi+fif_j=-a_{x_j+1}b_{y_i}+f_ifj?=?axj?+1?byi??+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]教科书般