[LOJ10186]任務安排
阿新 • • 發佈:2018-12-12
試題分析
一道斜率優化的dp
易得方程$f[j]=(S+t[i])\times c[j]+f[i]-t[i]\times c[i]+s\times c[n]$,為什麼要寫成這要,因為這樣其實就可以將$min$拆掉,並且是一個函式形式,$(S+t[i])$為斜率,$f[i]-t[i]\times c[i]+s\times c[n]$為截距。
並且當我們要決策$i$用哪一個j時,我們會發現斜率是一樣的,就只有截距會不同。所以我們要讓截距越短。
所以發現當斜率為上升時,即為下凸殼的形式,所以我們可以用單調佇列去優化
但是$t$有可能是負數,我們將線進行平移的時候要保證此點之前的斜率都小於$k$,之後全大於$k$,所以需要二分找到此區間
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<queue> #include<climits> #define int long long using namespace std; inline int read(){ int f=1,ans=0;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}View Codewhile(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } const int N=300001; int l,r,num[N]; int f[N],t[N],c[N],S,n,que[N]; int query(int pos,int X){ int L=l,R=r,maxn=0; int mid; while(L<=R){ mid=L+R>>1; if(f[que[mid+1]]-f[que[mid]]<=X*(c[que[mid+1]]-c[que[mid]])) L=mid+1,maxn=max(maxn,mid); else R=mid-1; } return que[maxn+1]; } signed main(){ n=read(),S=read(); for(int i=1;i<=n;i++) t[i]=t[i-1]+read(),c[i]=c[i-1]+read(); l=1,r=1;f[0]=0; for(int i=1;i<=n;i++){ int H=query(i,S+t[i]); f[i]=f[H]-(S+t[i])*c[H]+t[i]*c[i]+S*c[n]; while(l<r&&(f[que[r]]-f[que[r-1]])*(c[i]-c[que[r]])>=(f[i]-f[que[r]])*(c[que[r]]-c[que[r-1]])) r--; que[++r]=i; }printf("%lld\n",f[n]); return 0; }