Description
给出二维平面上的n个点,求有多少条经过原点的直线满足,所有点在其上的投影是对称的。
若有无数条输出-1
n<=2000
Solution
根据一些脑洞+结论我们知道对称中心一定是原点集的重心在直线上的投影
如果两个点关于重心中心对称那么这两个点在任意一条直线上都是对称的,删去
枚举两个点,钦定它们对称,容易发现直线是唯一的,这样我们得到了O(n^2)条直线
一条直线合法的必要条件是出现过>=n/2次,这样的直线只有O(n)条,可以暴力判断,判断一次是O(n)的
复杂度O(n^2 log n^2),瓶颈在排序
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef double db;
const int N=2e3+5,M=N*N;
const db eps=1e-6;
struct P{
db x,y;
P(db _x=0,db _y=0) {x=_x;y=_y;}
friend P operator + (P a,P b) {return P(a.x+b.x,a.y+b.y);}
friend P operator - (P a,P b) {return P(a.x-b.x,a.y-b.y);}
friend P operator * (P a,db x) {return P(a.x*x,a.y*x);}
}p[N],q[N],h;
int n,tot,ans;
bool vis[N];
struct node{
P p;
int a,b;
db k;
}a[N*N];
bool cmp(node a,node b) {return a.k<b.k;}
db cross(P a,P b) {return a.x*b.y-a.y*b.x;}
db dot(P a,P b) {return a.x*b.x+a.y*b.y;}
db len(P a) {return sqrt(dot(a,a));}
int sgn(db x) {
if (fabs(x)<eps) return 0;
if (x>0) return 1;
return -1;
}
bool check(node L,P p) {return fabs(dot(p-h,L.p))<eps;}
int main() {
scanf("%d",&n);
fo(i,1,n) {
scanf("%lf%lf",&q[i].x,&q[i].y);
h=h+q[i];
}
h=h*(1.0/n);
fo(i,1,n-1)
fo(j,i+1,n)
if (!sgn(cross(q[i]-h,q[j]-h))&&fabs(len(q[i]-h)-len(q[j]-h))<eps) {
vis[i]=vis[j]=1;
continue;
}
int tmp=0;
fo(i,1,n) if (!vis[i]) p[++tmp]=q[i];
n=tmp;
if (n<=2) {puts("-1");return 0;}
fo(i,1,n-1)
fo(j,i+1,n) {
db x=p[i].x+p[j].x-2*h.x;
db y=p[i].y+p[j].y-2*h.y;
a[++tot].p.x=y;a[tot].p.y=-x;
a[tot].a=i;a[tot].b=j;
if (a[tot].p.x<0) a[tot].p.x=-a[tot].p.x,a[tot].p.y=-a[tot].p.y;
if (fabs(a[tot].p.x)<eps) a[tot].p.y=fabs(a[tot].p.y);
if (fabs(a[tot].p.y)<eps) a[tot].p.x=fabs(a[tot].p.x);
a[tot].k=atan2(a[tot].p.y,a[tot].p.x);
}
sort(a+1,a+tot+1,cmp);
for(int l=1,r=0;l<=tot;l=r+1) {
while (r<tot&&!sgn(cross(a[r+1].p,a[l].p))) r++;
if (r-l+1>=n/2) {
fo(i,1,n) vis[i]=0;
fo(i,l,r) if (!vis[a[i].a]&&!vis[a[i].b]) vis[a[i].a]=vis[a[i].b]=1;
int cnt=0,id=0;
fo(i,1,n)
if (!vis[i]) {
cnt++;
id=i;
}
if (cnt>0&&!(n&1)||cnt>1&&(n&1)) continue;
if (!cnt||check(a[l],p[id])) ans++;
}
}
printf("%d\n",ans);
return 0;
}