1 条题解
-
0
自动搬运
来自洛谷,原作者为

chenzhiyou12
* *搬运于
2025-08-24 23:16:15,当前版本为作者最后更新于2025-05-18 21:25:24,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
赛时 lg 榜和正式榜独占(大概是?)。
可惜队友没有做出 FIM,遗憾 rk7。
下面给出一种比较简单易懂的做法(如有锅请大佬指正)。
首先,对于最终值取 的情况,我们不难弄出一个人的最小操作次数,即 $cost(i)=\max({A-a_i,B-b_i,C-c_i,0})+\max({a_i-A,b_i-B,c_i-C,0})$。然后修改完所有的次数就是 。
题意转化为求 的最小值。
不难发现, 是分段凸函数,可以形象的理解为三位空间中一个表面粗糙的碗。
注意到 $A\in[\min(a_i),\max(a_i)],B\in[\min(b_i),\max(b_i)],C\in[\min(c_i),\max(c_i)]$。
按照直觉,我们可以先把 分别取成 三个数组的中位数,也就是让我们的起点尽量在“碗”靠内的位置。随后,因为 其实只在整点上有取值,所以我们可以不断地试图向 个方向上的整点跳,根据凸性,如果跳出来的更优,那么我们就应该跳。
怎么决定跳多长的距离呢?可以直接倍增(准确来说是“倍减”),我们设 $k=max(\max(a_i)-\min(a_i),\max(b_i)-\min(b_i),\max(c_i)-\min(c_i))$(为了覆盖整个碗面),如果有一次跳成功了,我们就继续尝试跳,否则就将 折半。还是因为只在整点取值,所以倍增一定能跳到最终最优的点(一定能凑出来整数)。
所以就有了代码:
#include<bits/stdc++.h> #define ll long long #define db double #define vi vector<int> #define pb push_back #define pii pair<int,int> #define mkp make_pair #define For(i,j,k) for(int i=j;i<=k;++i) #define Rof(i,j,k) for(int i=j;i>=k;--i) using namespace std; const int N=1e5+10,inf=0x3f3f3f3f; int n; vi a,b,c; ll f(int A,int B,int C){ ll ret=0; For(i,0,n-1){ int d1=A-a[i],d2=B-b[i],d3=C-c[i]; int v1=max({d1,d2,d3,0}); int v2=max({-d1,-d2,-d3,0}); ret+=v1+v2; } return ret; } int med(vi x){sort(x.begin(),x.end());return x[x.size()/2];} int mn(vi x){ int ret=inf; for(auto v:x){ret=min(ret,v);} return ret; } int mx(vi x){ int ret=0; for(auto v:x){ret=max(ret,v);} return ret; } int main(){ ios::sync_with_stdio(false); cin.tie(NULL),cout.tie(NULL); cin>>n; For(i,1,n){ int na,nb,nc;cin>>na>>nb>>nc; a.pb(na),b.pb(nb),c.pb(nc); } int A=med(a),B=med(b),C=med(c); ll ans=f(A,B,C); int mna=mn(a),mxa=mx(a); int mnb=mn(b),mxb=mx(b); int mnc=mn(c),mxc=mx(c); int stp=max({mxa-mna,mxb-mnb,mxc-mnc}); while(stp){ bool flg=false; For(i,-1,1){For(j,-1,1){For(k,-1,1){ int na=A+i*stp,nb=B+j*stp,nc=C+k*stp;ll now=f(na,nb,nc); if(now<ans){ ans=now; A=na,B=nb,C=nc; flg=true; } }}} if(!flg){stp>>=1;} } cout<<ans<<'\n'; return 0; }下面证明 的凸性。
首先我们知道,若 和 均为凸函数, 也是凸函数。
我们先证一个引理:
若 ,其中 均为仿射函数(形如 的函数),则 是凸函数。
证明:
可以先取两个向量 和 。
有
整理就是:,符合凸函数的定义。
有了这个引理之后就好弄了。
$cost(i)=\max({A-a_i,B-b_i,C-c_i,0})+\max({a_i-A,b_i-B,c_i-C,0})$,不难发现, 都是仿射函数,所以 和 都是凸函数,所以 是凸函数。
因为 是凸函数,证得 也是凸函数。
- 1
信息
- ID
- 12285
- 时间
- 1500ms
- 内存
- 512MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者