1. 程式人生 > >[SDOI2012]任務安排 BZOJ2726 斜率優化+二分查找

[SDOI2012]任務安排 BZOJ2726 斜率優化+二分查找

一段 IV cmp cst esp std long 滿足 讓我

網上的題解...狀態就沒有一個和我一樣的...這讓我有些無從下手...

分析:

我們考慮,正常的斜率優化滿足x(i)單調遞增,k(i)單調遞增,那麽我們就可以只用維護一個單調隊列滿足對於當前的x(i)有最小值即可,因為x(i)滿足單調遞增。這樣的話,我們就可以維護一個單調隊列讓隊首元首最小。而這道題,可以發現有部分數據滿足x(i)單調遞增,那麽直接裸上就可以,但是由於時間有負數,所以x(i)並不滿足單調性。但是由於k(i)仍然滿足單調性,因此,我們依然可以發現更新x(i)的時候滿足斜率優化的性質,也就是我們已經可以將已經完全被覆蓋的直線忽略。(即:我們依然可以維護一個大凹包)

考慮n^2的DP方程:f[i]表示當前的最後一段區間在以i為終點時的最小花費。

轉移:f[i]=min{f[j]+(sum1[i]-sum1[j]+m)*(sum2[n]-sum2[j])};

之後,我們發現在我們維護的隊列中,對於相同的x(i),不同的j,更新的f[i]具有單峰性,那麽導函數具有單調性,二分導函數,找到最大值,之後更新答案,剩下的就是斜率優化的常規操作了。

附上代碼:

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <iostream>
using namespace std;
#define N 300005
#define ll long long
#define K(x) (-sum2[x])
#define B(x) (f[x]-sum1[x]*sum+sum1[x]*sum2[x]-m*sum2[x])
#define Y(x,y) (K(y)*sum1[x]+B(y))
int n,q[N];
ll f[N],sum1[N],sum2[N],sum,m;
bool cmp(int i,int j,int k)
{
	ll t1=(K(j)-K(k))*(B(i)-B(k));
	ll t2=(K(i)-K(k))*(B(j)-B(k));
	return t1<=t2;
}
bool check(int p1,int p2,int i)
{
	return /*f[p2]-sum2[p2]*(sum1[i]+m)*/Y(i,p2)</*f[p1]-(sum1[i]+m)*sum2[p1]*/Y(i,p1);
}
int main()
{
	scanf("%d%lld",&n,&m);
	for(int i=1,x,y;i<=n;i++)
	{
		scanf("%d%d",&x,&y);
		sum1[i]=sum1[i-1]+x;
		sum2[i]=sum2[i-1]+y;
	}
	sum=sum2[n];int t=0;memset(f,0x3f,sizeof(f));f[0]=0;
	for(int i=1;i<=n;i++)
	{
		int l=0,r=t;
		while(l<r)
		{
			int mid=(l+r)>>1;
			if(check(q[mid],q[mid+1],i))l=mid+1;
			else r=mid;
		}
		// printf("%d\n",q[l]);
		f[i]=Y(i,q[l])+sum*sum1[i]+m*sum;
		while(t&&cmp(q[t-1],q[t],i))t--;
		q[++t]=i;
	}
	printf("%lld\n",f[n]);return 0;
}

  

[SDOI2012]任務安排 BZOJ2726 斜率優化+二分查找