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;
}