Official
When no more move can be made, the minimum side of a drawable square is $\max(\max(X')-\min(X'), \max(Y')-\min(Y'))$.
We divide into two cases depending on the ordering between the two terms $\chi=\max(X')-\min(X')$ and $\gamma=\max(Y')-\min(Y')$ in $\max$.
Instead, notice that the values $\min(X'), \max(X'), \min(Y'), \max(Y')$ are updated at most $2N$ times, and perform operations in bulk until they change.
The more you move $\min(X')$ or $\max(X')$, the more points you need to do so. In other words, the cost to shift them by $1$ increases (weakly) monotonically.
By this property, for a fixed $\chi$, one can modify a sequence of operations not conforming to the greedy algorithm above to one that does, without increasing the number of times to move points.
F - Minimize Bounding Square Editorial by en_translator
We give you some hints for this problem. Click each item to reveal it.
Hint 1
In this problem, $x$ and $y$ coordinates can be considered independently.Hint 2
There is a greedy solution.Editorial
Let $X'$ be the sequence of the $x$ coordinates of the given points, and $Y'$ be that of $y$.When no more move can be made, the minimum side of a drawable square is $\max(\max(X')-\min(X'), \max(Y')-\min(Y'))$.
We divide into two cases depending on the ordering between the two terms $\chi=\max(X')-\min(X')$ and $\gamma=\max(Y')-\min(Y')$ in $\max$.
- If $\chi < \gamma$
- Modifying an $x$ coordinate does not change the value to minimize, so we leave it for now. For the $y$ coordinates, we should shift (in the proper direction) either those with $\max(Y')$ or those with $\min(Y')$, whichever fewer, to reduce $\gamma$ by one; otherwise, there is no room of improvement.
- Same applies if $\chi > \gamma$.
- If $\chi = \gamma$
- In this case, we can either regard $\chi < \gamma$ to reduce $\gamma$ by one first, or reduce both $\chi$ and $\gamma$ by one.
Instead, notice that the values $\min(X'), \max(X'), \min(Y'), \max(Y')$ are updated at most $2N$ times, and perform operations in bulk until they change.
Brief Proof
First, it is obviously no use making $\min(X')$ smaller or $\max(X')$ larger; we always try to bring them closer.The more you move $\min(X')$ or $\max(X')$, the more points you need to do so. In other words, the cost to shift them by $1$ increases (weakly) monotonically.
By this property, for a fixed $\chi$, one can modify a sequence of operations not conforming to the greedy algorithm above to one that does, without increasing the number of times to move points.
Sample code (C++):
#include<bits/stdc++.h>
using namespace std;
using pl=pair<long long,long long>;
int main(){
long long n,k;
cin >> n >> k;
vector<long long> x(n),y(n);
map<long long,long long> mx,my;
for(long long i=0;i<n;i++){
cin >> x[i] >> y[i];
mx[x[i]]++;
my[y[i]]++;
}
vector<pl> xv,yv;
for(auto &nx : mx){
xv.push_back(nx);
}
for(auto &nx : my){
yv.push_back(nx);
}
long long xl=0,xr=xv.size()-1;
long long yl=0,yr=yv.size()-1;
while(k>0){
long long gx=xv[xr].first-xv[xl].first;
long long gy=yv[yr].first-yv[yl].first;
long long fx,fy;
long long hx,hy;
long long cx,cy;
if(gx!=0){
if(xv[xl].second<xv[xr].second){
hx=xv[xl+1].first-xv[xl].first;
cx=xv[xl].second;
fx=-1;
}
else{
hx=xv[xr].first-xv[xr-1].first;
cx=xv[xr].second;
fx=1;
}
}
if(gy!=0){
if(yv[yl].second<yv[yr].second){
hy=yv[yl+1].first-yv[yl].first;
cy=yv[yl].second;
fy=-1;
}
else{
hy=yv[yr].first-yv[yr-1].first;
cy=yv[yr].second;
fy=1;
}
}
if(gx==0 && gy==0){break;}
else if(gx<gy){
// shorten y
long long opt=min({k/cy,hy,gy-gx});
if(opt==0){break;}
k-=cy*opt;
if(fy==-1){yv[yl].first+=opt;}
else{yv[yr].first-=opt;}
}
else if(gx>gy){
// shorten x
long long opt=min({k/cx,hx,gx-gy});
if(opt==0){break;}
k-=cx*opt;
if(fx==-1){xv[xl].first+=opt;}
else{xv[xr].first-=opt;}
}
else{
// once x==y, let's keep it
// shorten x&y
long long opt=min({k/(cx+cy),hx,hy});
if(opt==0){break;}
k-=(cx+cy)*opt;
if(fy==-1){yv[yl].first+=opt;}
else{yv[yr].first-=opt;}
if(fx==-1){xv[xl].first+=opt;}
else{xv[xr].first-=opt;}
}
if(xl!=xr){
if(xv[xl].first==xv[xl+1].first){
xv[xl+1].second+=xv[xl].second;
xl++;
}
else if(xv[xr].first==xv[xr-1].first){
xv[xr-1].second+=xv[xr].second;
xr--;
}
}
if(yl!=yr){
if(yv[yl].first==yv[yl+1].first){
yv[yl+1].second+=yv[yl].second;
yl++;
}
else if(yv[yr].first==yv[yr-1].first){
yv[yr-1].second+=yv[yr].second;
yr--;
}
}
}
{
long long gx=xv[xr].first-xv[xl].first;
long long gy=yv[yr].first-yv[yl].first;
cout << max(gx,gy) << "\n";
}
return 0;
}
posted:
last update: