https://codeforces.com/contest/1355/problem/E
这场难度c>a>e>d,作为e题偏水,d题更偏水,a又是机智题我没get到点,20分钟看了3k人过了果断换成小号打,结果发现好像打大号也能上分。
假设最后的高度是h,需要添加的砖头总数是dec,需要拿走的砖头总数是res,根据,a,r,m的关系,我们要么尽可能使用a,要么尽可能使用b,要么尽可能是用m。
那么就对所有高度排序,由于相邻高度之间的花费是一个一次函数,那么一定在端点取到最小值。
注意第3个样例,如果要尽量取m,那么高度是sum/n,sum/n+1的时候m最多,a,r最少,所以也要把这两个高度加进去离散化。
离散化以后对每个高度有多少个位置,搞个前缀和,就可以O(1)转移dec和res了
然后选取也只有两种情况,要么取a和r,要么尽量去m
其实还可以三分高度以后O(n)判断,一样的
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxl=3e5+10;
int n,cas,tot;
ll ans,a,r,m;
int h[maxl],num[maxl];
ll b[maxl],sum[maxl];
char s[maxl];
bool in[maxl];
inline int id(int x)
{
return lower_bound(num+1,num+1+tot,x)-num;
}
inline void prework()
{
ll cnt=0;
scanf("%d%lld%lld%lld",&n,&a,&r,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&h[i]);
num[++tot]=h[i];cnt+=h[i];
}
num[++tot]=cnt/n;num[++tot]=cnt/n+1;
sort(num+1,num+1+tot);
tot=unique(num+1,num+1+tot)-num-1;
for(int i=1;i<=n;i++)
b[id(h[i])]++;
for(int i=1;i<=tot;i++)
sum[i]=sum[i-1]+b[i];
}
inline void mainwork()
{
ll tmp1,tmp2,ned=0,res=0,mi;
for(int i=1;i<=n;i++)
res+=(h[i]-num[1]);
tmp1=res*r;ans=tmp1;
for(int i=2;i<=tot;i++)
{
res-=(sum[tot]-sum[i-1])*(num[i]-num[i-1]);
ned+=sum[i-1]*(num[i]-num[i-1]);
mi=min(res,ned);
tmp1=(ned-mi)*a+(res-mi)*r+mi*m;
tmp2=ned*a+res*r;
ans=min(ans,min(tmp1,tmp2));
}
}
inline void print()
{
printf("%lld\n",ans);
}
int main()
{
int t=1;
//scanf("%d",&t);
for(cas=1;cas<=t;cas++)
{
prework();
mainwork();
print();
}
return 0;
}