luogu P2900 [USACO08MAR]土地征用Land Acquisition

背景:

晚上还是去了物理竞赛。
好无聊,垃圾卷子。
半路溜了回来(只上了一节课)。

题目传送门:

https://www.luogu.org/problemnew/show/P2900

题意:

a i ∗ b i a_i*b_i aibi n n n块地,其中,可以任选一些组成一组购买,且最后要买完(可以买多组),每一组的其价值是 x = max ⁡ { a i } ∗ max ⁡ { b i } x=\max\{ a_i\}*\max\{b_i\} x=max{ai}max{bi}。最后的贡献是 ∑ x \sum x x。求贡献的最小值。

思路:

对于 a j ≤ a i a_j≤a_i ajai b j ≤ b i b_j≤b_i bjbi的土地 j j j自然是没有用的,因此可以删掉。可以采用排序然后删除的方式。
具体来说就是按照 a a a升序, b b b降序,那么对于相等的 a a a,考虑 b b b即可。用一个 a ′ , b ′ a',b' a,b分别存储剩下的有效的土地。

剩下的还是基本套路。
f i f_i fi表示购买前 i i i块地的最小费用。
则状态转移方程为: f i = min ⁡ j = 1 i − 1 f j + a j + 1 ′ ∗ b i ′ f_i=\min_{j=1}^{i-1}f_j+a'_{j+1}*b_i' fi=minj=1i1fj+aj+1bi

这里解释一下这个方程,从 j + 1 j+1 j+1 i i i的区间里( j j j已经被包含在 f j f_j fj里了,因此是从 j + 1 j+1 j+1开始的),这些土地的贡献是 max ⁡ { a k ′ } ∗ max ⁡ { b k ′ } , k ∈ [ j + 1 , r ] \max\{a'_k\}*\max\{b'_k\},k∈[j+1,r] max{ak}max{bk},k[j+1,r],又因为我们是对 a a a升序, b b b降序排的,所以我们的 max ⁡ { a k ′ } = a j + 1 ′ , max ⁡ { b k ′ } = b i ′ \max\{a'_k\}=a'_{j+1},\max\{b'_k\}=b'_i max{ak}=aj+1,max{bk}=bi

同理,得出斜率方程: f j − f k a k + 1 ′ − a j + 1 ′ &lt; b i ′ \frac{f_j-f_k}{a&#x27;_{k+1}-a&#x27;_{j+1}}&lt;b&#x27;_i ak+1aj+1fjfk<bi
同理,在套进去即可。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
	int n,t=0;
	int que[100010];
	LL f[100010];
	struct node{LL x,y;} a[100010],d[100010];
bool cmp(node x,node y)
{
	return x.x==y.x?x.y<y.y:x.x>y.x;
}
double calc(int x,int y)
{
	return ((double)f[y]-f[x])/((double)a[x+1].x-a[y+1].x);
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%lld %lld",&d[i].x,&d[i].y);
	sort(d+1,d+n+1,cmp);
	LL ma=0;
	for(int i=1;i<=n;i++)
		if(d[i].y>ma) ma=d[i].y,a[++t]=d[i];
	int head=1,tail=1;
	que[1]=0;
	for(int i=1;i<=t;i++)
	{
		while(head<tail&&calc(que[head],que[head+1])<=(double)a[i].y) head++;
		f[i]=f[que[head]]+a[que[head]+1].x*a[i].y;
		while(head<tail&&calc(que[tail],i)<=calc(que[tail-1],que[tail])) tail--;
		que[++tail]=i;
	}
	printf("%lld",f[t]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值