P2748 [USACO16OPEN]Landscaping P

题目链接

题意分析

由于(A_i,B_i≤10) 所以我们可以考虑把所有的泥土都分开讨论

也就相当于

2,3,1,4

转化之后就是如下

1,1,2,2,2,3,4,4,4,4

然后我们只考虑多出来或者少出来的泥土

如果当前是多的 那么我们就需要Y代价移走

到了下一个少的泥土时候 我们就存在两种选择

1.花费X代价购买一泥土

2.花费Z|i-j|的代价移入一泥土

我们考虑顺序扫描使得j>i

那么新增代价就是(Min{(j-i)z-Y,X})

或者说 (Min{jz-(iz+Y),X})

左边是因为我们从i这个位置移进泥土 所以也就减去了移走泥土的Y的代价

然后我们就计算好了当前的新增代价 为cost

那么再到了位置k的时候 还是少的 考虑一下j(仅仅是为了解释过程 不考虑合理性)

那么新增代价就是(Min{(k-j)z-cost,X})

也就是(Min{kz-(jz+cost),X})

左边是因为我们从j这个位置移进泥土 所以也就减去了j移动泥土的cost的代价

当然真正操作的时候 多出来的泥土和少出来的泥土我们是要分开处理的

注意一下 上面我们转成了一个特殊形式(Min{jz-(iz+Y),X})以及(Min{kz-(jz+cost),X})

所以我们对于当前处理完了一个答案之后 直接就可以得出TA对接下来的答案的贡献 ((jz+cost))

然后我们开两个堆就可以直接维护了

CODE:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#define N 100005
#define inf 1e18
using namespace std;
priority_queue<long long> cdy,wzy;
long long n,X,Y,Z;
long long num1[N],num2[N];
long long ans;
void work1(long long now)
{
	long long cost=inf;
	if(!wzy.empty())
	{
		long long tx=wzy.top(),tmp=now*Z-tx;
		if(tmp<Y) cost=tmp,wzy.pop(),cdy.push(now*Z+tmp);
	}
	if(cost==inf) cost=Y,cdy.push(now*Z+Y);
	ans+=cost;
}

void work2(long long now)
{
	long long cost=inf;
	if(!cdy.empty())
	{
		long long tx=cdy.top(),tmp=now*Z-tx;
		if(tmp<X) cost=tmp,cdy.pop(),wzy.push(now*Z+tmp);
	}
	if(cost==inf) cost=X,wzy.push(now*Z+X);
	ans+=cost;
}
int main()
{
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	cin>>n>>X>>Y>>Z;
	for(long long i=1;i<=n;++i)
	cin>>num1[i]>>num2[i];
	for(long long i=1;i<=n;++i)
	{
		for(long long j=1;j<=abs(num1[i]-num2[i]);++j)
		{
			if(num1[i]>num2[i]) work1(i);
			else work2(i);
		}
	}
	cout<<ans<<endl;
	return 0;
} 
原文地址:https://www.cnblogs.com/LovToLZX/p/13889332.html