Eureka
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2317 Accepted Submission(s): 678
Problem Description
Professor Zhang draws n points on the plane, which are conveniently labeled by 1,2,...,n. The i-th point is at (xi,yi). Professor Zhang wants to know the number of best sets. As the value could be very large, print it modulo 109+7.
A set P (P contains the label of the points) is called best set if and only if there are at least one best pair in P. Two numbers u and v (u,v∈P,u≠v) are called best pair, if for every w∈P, f(u,v)≥g(u,v,w), where f(u,v)=(xu−xv)2+(yu−yv)2−−−−−−−−−−−−−−−−−−√ and g(u,v,w)=f(u,v)+f(v,w)+f(w,u)2.
A set P (P contains the label of the points) is called best set if and only if there are at least one best pair in P. Two numbers u and v (u,v∈P,u≠v) are called best pair, if for every w∈P, f(u,v)≥g(u,v,w), where f(u,v)=(xu−xv)2+(yu−yv)2−−−−−−−−−−−−−−−−−−√ and g(u,v,w)=f(u,v)+f(v,w)+f(w,u)2.
Input
There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:
The first line contains an integer n (1≤n≤1000) -- then number of points.
Each of the following n lines contains two integers xi and yi (−109≤xi,yi≤109) -- coordinates of the i-th point.
The first line contains an integer n (1≤n≤1000) -- then number of points.
Each of the following n lines contains two integers xi and yi (−109≤xi,yi≤109) -- coordinates of the i-th point.
Output
For each test case, output an integer denoting the answer.
Sample Input
3
3
1 1
1 1
1 1
3
0 0
0 1
1 0
1
0 0
Sample Output
4
3
0
Author
zimpha
Source
Recommend
题意:定义在同一直线上至少两个点(可以重合)就可以组成一个完美集合,比如点1,3,5共线,那么就有(1,3)(3,5)(1,5)和(1,3,5)四个集合,现在给你n个点的坐标,求有多少个这样的集合;
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <algorithm>
#include <set>
using namespace std;
typedef long long ll;
typedef unsigned long long Ull;
#define MM(a,b) memset(a,b,sizeof(a));
const double eps = 1e-10;
const int inf =0x7f7f7f7f;
const double pi=acos(-1);
const int mod=1e9+7;
const int maxn=100000+10;
ll f_2[1000+10];
struct Point{
int x,y;
}p[1000+10];
struct Ang{
double a;
ll x,y;
}ang[1000+10];
bool cmpxy(Point a,Point b)
{
if(a.x!=b.x) return a.x<b.x;
else return a.y<b.y;
}
bool cmpang(Ang a,Ang b){
return a.a<b.a;
}
int main()
{
f_2[0]=1;
for(int i=1;i<=1000;i++) f_2[i]=(f_2[i-1]*2)%mod;
int cas,n;
scanf("%d",&cas);
while(cas--)
{
ll ans=0;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d %d",&p[i].x,&p[i].y);
sort(p+1,p+n+1,cmpxy);
int i,j,k,l,num;
for(i=1;i<n;i++)
{
for(j=i+1;j<=n;j++)
{
if(p[j].x==p[i].x&&p[j].y==p[i].y) continue;
else break;
}
j--;
int s=j-i+1,cnt=0,d=0;
ans=(ans+f_2[s]-1-s)%mod;
for(k=j+1;k<=n;k++)
{
ang[++cnt].a=atan2((double)(p[k].y-p[i].y),(double)(p[k].x-p[i].x));
ang[cnt].x=p[k].x;
ang[cnt].y=p[k].y;
}
sort(ang+1,ang+cnt+1,cmpang);
for(k=1;k<=cnt;k++){
for(l=k+1;l<=cnt;l++)
if((ang[l].y-p[i].y)*(ang[k].x-p[i].x)!=
(ang[k].y-p[i].y)*(ang[l].x-p[i].x))
{d++;break;}
l--;
num=l-k+1;
ans=(ans+((f_2[s]-1)*(f_2[num]-1))%mod)%mod;
k=l;
}
i=j;
}
printf("%lld
",ans%mod);
}
return 0;
}
思路:先对所有的点进行坐标排序,然后依次枚举每个点,先筛选出与其重合的点,然后,
再依次为基点,求得没有枚举过得点相对这个点的角度,再进行极角排序,合并共线的点(这个
判断共线容易错。不能直接根据相对基点角度(double型)是否相等来判断,可以直接用向量
共线的坐标,变成相乘的形式)