Problem
Solution
- 为方便操作将坐标放至第一象限处理,对不同的x建立“桶”,将y从小到大放进其对应的桶,然后对桶两两比对找两桶之间最小的y的差。期间维护答案,最后对原数据进行扫描找到最终答案。
- 由于每个桶中的y都是升序的,比对两个桶中最小的y的差只需同时将两桶扫一遍,最差时间复杂度O(n2/t),t>=10,刚好超时。
- 考虑剪枝,如果两桶的x距离已经大于等于当前最优答案,此时不必再枚举第二个桶,继续枚举第一个桶即可。实测使用此优化在cf上效率提高10倍+,但实际上也可以卡,比如在极限形况下y在相邻桶的桶底桶底交错分布。
- 有效的剪枝都可以加上去,出题人不一定对针对各种剪枝出专门卡掉这些剪枝的数据。
- 主要各部分的处理尽量减小常数。
Code
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
vector<int>a[10005];
int n,x[100005],y[100005],ansx1,ansx2,ansy1,ansy2,que[10005],cnt,ac1,ac2,wa1,wa2;
struct node{
int x,y;
}nd[100005];
bool cmp1(const node &c,const node &b)
{
return c.y<b.y;
}
bool cmp2(const node &c,const node &b)
{
return c.x<b.x;
}
double ac=1e9;
int main()
{
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&x[i],&y[i]);
nd[i].x=abs(x[i]);
nd[i].y=abs(y[i]);
}
sort(nd+1,nd+1+n,cmp1);
for(int i=1;i<=n;i++)
a[nd[i].x].push_back(nd[i].y);
sort(nd+1,nd+1+n,cmp2);
que[++cnt]=nd[1].x;
for(int i=2;i<=n;i++)
if(nd[i].x!=nd[i-1].x)
que[++cnt]=abs(nd[i].x);
for(int i=1;i<cnt;i++)
{
for(int j=i+1;j<=cnt;j++)
{
if(j-i>=ac) break;
int l=que[i],r=que[j],len1=a[l].size(),len2=a[r].size(),k=0,ans=len1+len2,k1=0,k2=0,dis=1e9,pos1,pos2;
while(k1+k2<ans-2)
{
if(abs(a[l][k1]-a[r][k2])<dis)
{
dis=abs(a[l][k1]-a[r][k2]);
pos1=a[l][k1];
pos2=a[r][k2];
}
if(k1==len1-1||k2==len2-1)
k1==len1-1?k2++:k1++;
else{
if(a[l][k1]>a[r][k2])
k2++;
else
k1++;
}
}
if(abs(a[l][k1]-a[r][k2])<dis)
{
dis=abs(a[l][k1]-a[r][k2]);
pos1=a[l][k1];
pos2=a[r][k2];
}
if(sqrt(dis*dis+(r-l)*(r-l))<ac)
{
ac=sqrt(dis*dis+(r-l)*(r-l));
ansx1=l;
ansx2=r;
ansy1=pos1;
ansy2=pos2;
}
}
}
for(int i=1;i<=cnt;i++)
{
int nw=que[i],dis=1e9,pos1,pos2;
for(int j=1;j<a[nw].size();j++)
{
if(a[nw][j]-a[nw][j-1]<dis)
{
dis=a[nw][j]-a[nw][j-1];
pos1=a[nw][j-1];
pos2=a[nw][j];
}
}
if(dis!=1e9&&sqrt(dis*dis)<ac)
{
ac=sqrt(dis*dis);
ansx1=ansx2=nw;
ansy1=pos1;
ansy2=pos2;
}
}
for(int i=1;i<=n;i++)
{
if(abs(x[i])==ansx1&&abs(y[i])==ansy1&&!wa1)
{
wa1=i;
if(x[i]!=ansx1)
ac1=y[i]==ansy1?2:4;
else
ac1=y[i]==ansy1?1:3;
}
if(abs(x[i])==ansx2&&abs(y[i])==ansy2&&i!=wa1)
{
wa2=i;
if(x[i]==ansx2)
ac2=y[i]==ansy2?4:2;
else
ac2=y[i]==ansy2?3:1;
}
}
cout<<wa1<<' '<<ac1<<' '<<wa2<<' '<<ac2;
return 0;
}