题解:B4103 [CSP-X2023 山东] 代价

· · 题解

目前没有人发二分做法,我先交一发题解。

题意

有一个长度为 n 的序列 a,每次可以花费 A 的代价将 a_i+1,也可以花费 B 的代价将 a_i-1,求将 a 序列全部变成相同的一个数的最小代价。

思路

注意到 n \le 10^5,a_i \le 10^9,可以使用 O(n \log a_i) 的做法。

考虑二分值域。

设序列中最小值为 minn,最大值为 maxn

贪心的想,最终的答案一定在 [minn,maxn] 之间。

所以把左边界 l 赋为 minn,右边界 r 赋为 maxn,进行二分。

总时间复杂度:$O(n\log a_i)$。 注意当 $minn=maxn$ 时要特判输出 $0$。 ### Code ```c++ #include<bits/stdc++.h> #define bug cout<<"songge888"<<'\n'; #define int long long using namespace std; int n,a,b,v[100010],l=1e18,r,ret; int f(int x){ int s=0; for(int i=1;i<=n;i++){ if(v[i]<x){ s+=(x-v[i])*a; } else{ s+=(v[i]-x)*b; } } return s; } signed main(){ cin>>n>>a>>b; for(int i=1;i<=n;i++){ cin>>v[i]; l=min(l,v[i]); r=max(r,v[i]); } if(l==r){ cout<<0<<endl; return 0; } while(l<=r){ int mid=(l+r)/2; if(f(mid)<=f(mid+1)){ ret=mid; r=mid-1; } else{ l=mid+1; } } cout<<f(ret)<<endl; return 0; } ```