【BZOJ1597】【Usaco2008 Mar】土地购买 斜率优化DP

题目:

题目在这里

思路与做法:

这题如果想要直接dp的话不太好处理。

不过, 我们发现如果\(a[i].x>=a[j].x\)\(a[i].y>=a[j].y\) \((\)a是输入的数组,x为长,y为宽\()\), j是没用的, 可以直接去掉, 然后就可以dp了

容易得出状态转移方程为:
\(f_i = min \{f_j + x_i * y_{j+1} \}\)

可以用斜率优化DP

推导过程:

\(f_j + x_i * y_{j+1} < f_k + x_i * y_{k+1}\)

\(f_j - f_k < x_i*y_{k+1} - x_i*y_{j+1}\)

\({f_j - _k \over y_{k+1} - y_{j+1}} < x_i\)

代码:

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cstdio>
#include <vector>
#include <algorithm>

using namespace std;

const int N = 50010;

struct Data
{   int x, y;
	bool operator < (const Data &rhs) const { return x < rhs.x || (x == rhs.x && y < rhs.y); }
} a[N];
vector<int> x, y;

int Q[N], hd, tl;
long long f[N];
inline double calc(int j, int k) { return (double)(f[j]-f[k]) / (double)(y[k+1]-y[j+1]); }

int main()
{   int n;
	scanf("%d", &n);
	for(int i=1; i<=n; i++)
		scanf("%d %d", &a[i].x, &a[i].y);
	sort(a+1, a+1+n);
	x.push_back(0);
	y.push_back(0);
	for(int i=1; i<=n; i++)
	{   while(x.size() > 1 && y.size() > 1 && y.back() <= a[i].y)
			x.pop_back(), y.pop_back();
		x.push_back(a[i].x);
		y.push_back(a[i].y);
	}
	Q[hd = 0] = 0;
	tl = 1;
	for(int i=1; i<x.size(); i++)
	{   while(hd < tl-1 && calc(Q[hd+1], Q[hd]) <= x[i]) hd++;
		f[i] = f[Q[hd]] + (long long)y[Q[hd]+1] * (long long)x[i];
		while(hd < tl-1 && calc(i, Q[tl-1]) <= calc(Q[tl-1], Q[tl-2])) tl--;
		Q[tl++] = i;
	}
	printf("%lld\n", f[x.size()-1]);
	return 0;
}
posted @ 2018-03-18 20:19  EZ_WYC  阅读(129)  评论(0编辑  收藏  举报