题意:
一个平面,每次增加一个点(x[i],y[i]),其坐标根据上一个点算出:(x[i-1] * Ax + Bx ) mod Cx,(y[i-1] * Ay + By ) mod Cy求出现有点集中的最近点对的距离的平方,共n个点( n <= 5*100000),求平方的和。
思路:
使用set容器,使加进去之后的序列按x递增排序。minn对距离进行约束,若x的平方差值已经大于minn了就退出。
#include<set>
#include<cstdio>
using namespace std;
const long long INF=1LL<<60;
const long long maxn=500001;
long long minn,ans,ax,bx,cx,ay,by,cy,i,n,T,kx,ky;
long long x[maxn],y[maxn];
struct point
{
long long x,y;
bool operator < (const point & p) const
{
return x<p.x;
}
};
int main()
{
scanf("%I64d", &T);
while(T--)
{
scanf("%I64d%I64d%I64d%I64d%I64d%I64d%I64d",&n,&ax,&bx,&cx,&ay,&by,&cy);
x[0]=0;
y[0]=0;
for(i=1;i<=n;i++)
{
x[i]=(x[i-1]*ax+bx)%cx;
y[i]=(y[i-1]*ay+by)%cy;
}
point p;
p.x=x[1];
p.y=y[1];
multiset<point> s;
multiset<point>::iterator it1,it2;
s.clear();
s.insert(p);
minn=INF;
ans=0;
for(i=2;i<=n;i++)
{
p.x=x[i];
p.y=y[i];
it1=s.lower_bound(p);
for(it2=it1;it2!=s.end();it2++)
{
kx=p.x-it2->x;
kx*=kx;
if(kx>=minn) break;
ky=p.y-it2->y;
ky*=ky;
if(minn>kx+ky) minn=kx+ky;
}
for(it2=it1;it2!=s.begin();)
{
it2--;
kx=p.x-it2->x;
kx*=kx;
if(kx>=minn) break;
ky=p.y-it2->y;
ky*=ky;
if(minn>kx+ky) minn=kx+ky;
}
s.insert(p);
ans+=minn;
}
printf("%I64d\n",ans);
}
return 0;
}