Minimum Sum
Codeforces 120J
这题可以转化成分治经典问题:求最近点对距离。值得注意,这题要开freopen
1.两个转化后的向量和的长度=sqrt((xi+xj)^2 +(yi+yj)^2 )。类似于最近点对的sqrt((xi-xj)^2 +(yi+yj)^2)
2.一个向量有四种变化,我们就把四种全都塞进去找最近点对。怕重复?多存一个id,不让id相同的点发生关系。
3.找到最近点对之后,由于式子有一些微妙的不同,但是向量可以任意转化啊,把其中一个点的x,y同时去负1,4相互转化,2,3相互转化。
4.为什么可以转化成最近点对呢?因为向量四种变化取遍时加减是可以相互转化的,即(xi-(-xj))=(xi+xj)
具体代码如下:
#include<bits/stdc++.h>
using namespace std;
const int M=1e5+5;
int n;
struct node {
int x,y,id,k;
bool operator <(const node&tmp)const {
return y<tmp.y;
}
void pt() {
printf("x=%d y=%d id=%d k=%d\n",x,y,id,k);
}
} A[M*4],FF[M*4];
int dx[5]= {0,1,-1,1,-1};
int dy[5]= {0,1,1,-1,-1};
bool cmp(node a,node b) {
return a.x<b.x;
}
void merge(int L,int R) {
int mid=L+R>>1;
int len1=L,len2=mid+1,len=L;
while(len1<=mid&&len2<=R) {
if(A[len1]<A[len2])FF[len++]=A[len1++];
else FF[len++]=A[len2++];
}
while(len1<=mid)FF[len++]=A[len1++];
while(len2<=R)FF[len++]=A[len2++];
for(int i=L; i<=R; i++)A[i]=FF[i];
}
int ansi,ansj,ansk1,ansk2;
long long ans=1e18;
long long solve(int L,int R) {
if(L>=R)return 1e18;
int mid=L+R>>1;
int x=A[mid].x;
long long d=min(solve(L,mid),solve(mid+1,R));
merge(L,R);
vector<node>B;
for(int i=L; i<=R; i++) {
if(1ll*(A[i].x-x)*(A[i].x-x)>=d)continue;
for(int j=B.size()-1; j>=0; j--) {
int dx=A[i].x-B[j].x,dy=A[i].y-B[j].y;
if(B[j].id==A[i].id||1ll*dy*dy>=d)continue;
if(1ll*dx*dx+1ll*dy*dy<d) {
d=1ll*dx*dx+1ll*dy*dy;
//printf("%lld %d %d\n",d,dx,dy);
if(d<ans) {
ans=d;
ansi=A[i].id,ansk1=A[i].k;
ansj=B[j].id,ansk2=B[j].k;
}
}
}
B.push_back(A[i]);
}
return d;
}
void check(int &x) {
if(x==1)x=4;
else if(x==2)x=3;
else if(x==3)x=2;
else x=1;
}
int main() {
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
scanf("%d",&n);
int len=n;
for(int i=1; i<=n; i++) {
scanf("%d %d",&A[i].x,&A[i].y);
A[i].id=i,A[i].k=1;
}
for(int k=2; k<=4; k++) {
for(int i=1; i<=len; i++) {
n++;
A[n]=A[i],A[n].k=k;
A[n].x*=dx[k],A[n].y*=dy[k];
}
}
sort(A+1,A+1+n,cmp);
solve(1,n);
check(ansk2);
printf("%d %d %d %d\n",ansi,ansk1,ansj,ansk2);
return 0;
}