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

题解:首先将块排个序,然后去掉被其它某块包含的块,然后斜率优化dp

dp方程:f[i]=f[j]+a[i]*b[j+1];

具体什么x啊y啊什么的在代码注释里面。


……。。。。纠结死了。开始各种WA,现在才发现:

inline long long xmul(Point i,Point j,Point k){(i.y-j.y)*(j.x-k.x)-(j.y-k.y)*(i.x-j.x);}
上面的代码竟然能通过编译……,无力吐槽。以后一定要用终端+Wall命令编译文件了。

warning一日不死,代码一日不跑!!!!

……调了好久好久好久啊。。。。。。。心痛啊。


#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 50500
#define inf 0x3f3f3f3f
/*
	f[j]=-a[i]*b[j+1]+f[i]
	y=f[j]
	x=b[j+1]
	k=-a[i] 保证a不降,即k不升
	b=f[i]

	维护上凸包
*/
using namespace std;
struct Point
{
	long long x,y;
	int id;
	Point(long long _x,long long _y,int _id):x(_x),y(_y),id(_id){}
	Point(){}
}now,que[N];
inline long long xmul(Point i,Point j,Point k){return(i.y-j.y)*(j.x-k.x)-(j.y-k.y)*(i.x-j.x);}
int n,l,r;
long long f[N];
struct Mrx
{
	long long a,b;
	bool operator < (const Mrx &c)const
	{if(a==c.a)return b<c.b;return a<c.a;}
}mrx[N];
int main()
{
//	freopen("test.in","r",stdin);
//	freopen("my.out","w",stdout);
	int i,j,k;
	scanf("%d",&n);
	for(i=1;i<=n;i++)scanf("%d%d",&mrx[i].a,&mrx[i].b);
	sort(mrx+1,mrx+n+1);
	int edl=0;
	long long maxx=0;
	for(i=n;i;i--)
	{
		if(mrx[i].b<=maxx)edl++,mrx[i].a=mrx[i].b=inf;
		else maxx=mrx[i].b;
	}
	sort(mrx+1,mrx+n+1);
	n-=edl;
	memset(f,0x3f,sizeof(f));
	f[0]=0;
	que[0].x=mrx[1].b;
	for(i=1;i<=n;i++)
	{
		int K=-mrx[i].a;
	//	while(l<r&&que[l].y-que[l+1].y>=(que[l].x-que[l+1].x)*K)l++; //斜率版
		while(l<r&&f[que[l].id]+mrx[i].a*mrx[que[l].id+1].b>=f[que[l+1].id]+mrx[i].a*mrx[que[l+1].id+1].b)l++; //函数值版
		now=Point(mrx[i+1].b,f[i]=f[que[l].id]+mrx[i].a*mrx[que[l].id+1].b,i);
		while(l<r&&xmul(now,que[r],que[r-1])>=0)r--;
	//	while(l<r&&(now.y-que[r].y)*(que[r].x-que[r-1].x)>=(que[r].y-que[r-1].y)*(now.x-que[r].x))--r;
		que[++r]=now;
	}
	cout<<f[n]<<endl;
	return 0;
}



。。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值