题目
题意: 给定长度为n的数组。有三种操作,求最小的花费使得数组中所有元素相同。
花费a,使得某个数++;
花费b,使得某个数–;
花费c,使得某个数+1,另一个数-1.
思路: 三分,函数值可以花O(n)的时间枚举得到,当然也可以维护前缀和二分求得。
那么为什么可以用三分呢,首先直接二分不太行,因为不具有单调性。
然后三分的使用条件就是具有极值点,假设最优解为所有数等于ans,那么ans不管是+1还是-1都会使答案变得更差或者不变(操作的消耗可能为0),所以可以三分找。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5+10;
//#define int long long
int a[N];
int n,m,k,T;
ll t1,t2,t3;
ll f(int x)
{
ll sum = 0;
ll sum1 = 0,sum2 = 0;
for(int i=1;i<=n;++i)
{
if(a[i]<x) sum1 += (x-a[i]); //小于
else sum2 += (a[i]-x); //大于
}
if(t3<t1+t2)
{
sum = 1ll*t3*min(sum1,sum2)+max(0ll,sum2-sum1)*t2+max(0ll,sum1-sum2)*t1;
}
else
{
sum = sum2*t2+sum1*t1;
}
return sum;
}
ll find(int l,int r)
{
int m1,m2; ll f1,f2;
while(l<r)
{
m1 = l+(r-l)/3;
m2 = r-(r-l)/3;
f1 = f(m1);
f2 = f(m2);
if(f1>f2) l = m1+1;
else r = m2-1;
}
// cout<<f(5)<<"??\n";
return min(f1,f2);
}
void solve()
{
cin>>n>>t1>>t2>>t3;
// ll mx = 0;
for(int i=1;i<=n;++i) cin>>a[i];
ll ans = find(0,1000000000);
cout<<ans;
}
signed main(void)
{
solve();
return 0;
}
/*
10 7122 8827 3205
452685204 144160553 743427456 403576146 888744473 313727757 22025193 886601085 576370788 787974081
*/