Eureka
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1747 Accepted Submission(s): 499
Total Submission(s): 1747 Accepted Submission(s): 499
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
题意:给你若干个点,任选两个不同的点(可以重合,但必须是两个点),求所有与这两个点共线的点数(本身也算),求有多少种选取方式。。
做法:很容易可以想到存储斜率,但不能用double,那就用向量的方式存储就好了。但是这里有几个要处理的地方;
1. 重合的点要如何处理。
2. 用向量存储的时候平行的向量会存到一起,但是题意是不被允许的。
多校赛的时候是想将向量存储的时候设置一个起点,用以区分平行向量。
但这个起点是有很多讲究的,故而并未处理成功。
后来参考了一个思路,确实是厉害.
1. 先将所有点排个序,这样可以保证向量都是非负的,去除相反向量带来的影响。
2. 用gcd的方式将向量的值最小化,使相同向量的唯一性。
当然这两步都比较正常,一般可以做到。
3. 取出一个点进行单独讨论,统计这一个点对总答案的贡献度。
这一步将向量平行的可能去除,把这个问题瞬间简单到非人的地步。。
当然这也是比较常用的方式,只不过大脑不太够用。
代码;
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
using namespace std;
struct node
{
int x,y;
bool operator<(const node&p)const
{
if(x!=p.x)
return x<p.x;
return y<p.y;
}
};
const int maxn=1001;
node A[maxn];
map<node,int>p;
map<node,int>::iterator it;
typedef long long ll;
const int mod=1e9+7;
ll num[maxn];
int main()
{
int T;
num[0]=1;
for(int i=1;i<maxn;i++)
{
num[i]=num[i-1]*2;
num[i]%=mod;
}
scanf("%d",&T);
while(T--)
{
int n;
ll ans=0;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d%d",&A[i].x,&A[i].y);
for(int i=0;i<n;i++)
{
int len=1;
p.clear();
for(int j=i+1;j<n;j++)
{
if(A[i].x==A[j].x&&A[i].y==A[j].y)
{
len++;
continue;
}
int xx=A[i].x-A[j].x,yy=A[i].y-A[j].y;
int k=__gcd(xx,yy);
if(k!=0)
{
xx/=k;
yy/=k;
}
p[node{xx,yy}]++;
}
if(len>1)
{
ans+=num[len-1]-1;
ans%=mod;
}
for(it=p.begin();it!=p.end();it++)
{
int mm=it->second;
ans+=((ll)num[len-1])*((ll)num[mm]-1);
ans%=mod;
}
}
printf("%I64d\n",ans);
}
return 0;
}