2016 Multi-University Training Contest 2 1005 hdu 5738 计算几何



链接:戳这里

Eureka
Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

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.
 
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.
 
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
 

思路:

先去重,题目要求的集合是一条线段。并且u,v是线段的两个端点。那么对于点集的每一条线段,都统计每一条的贡献

设线段上有k个点,那么贡献为即(C(k,2)+C(k,3)+...+C(k,k))=2^k-1-k。但是在多条线段的交点处如果恰好是g个重点存在

那么我们需要减去多算的,设该重点恰好在m条线段上,那么多算了(m-1)次。多算的贡献为(m-1)*((2^g)-g-1)

问题就变成了一条线段上有多少个点以及一个点出现在多少线段上。直接n*nlogn处理

注意卡精度,开long double 吧


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<iomanip>
#include<cmath>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
#define maxn 0x3f3f3f3f
#define MAX 1000100
#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
typedef unsigned long long ull;
#define mod 1000000007
#define INF (1ll<<60)-1
using namespace std;
const long double eps=1e-10;
int dcmp(long double x){
    if(fabs(x)<=eps) return 0;
    return x<0?-1:1;
}
struct point{
    long double x,y;
    point(long double x=0,long double y=0):x(x),y(y){}
    bool operator < (const point &a)const{
        if(dcmp(x-a.x)==0) return y<a.y;
        return x<a.x;
    }
};
bool operator == (const point &a,const point &b) {
    if(fabs(a.x-b.x)<=eps && fabs(a.y-b.y)<=eps)
        return true;
    return false;
}
point s[1010],p[1010];
struct edge{
    long double k,b;
    int A,B;
    bool operator < (const edge &a)const{
        if(dcmp(k-a.k)==0) return b<a.b;
        return k<a.k;
    }
}e[1000100];
map<point,int> mp;
int q[1010];
ll Pow[1010];
int main(){
    Pow[0]=1LL;
    for(int i=1;i<=1000;i++) Pow[i]=Pow[i-1]*2LL%mod;
    int T,n;
    scanf("%d",&T);
    while(T--){
        mp.clear();
        scanf("%d",&n);
        for(int i=1;i<=n;i++) {
            cin>>s[i].x>>s[i].y;
            mp[s[i]]++;
        }
        sort(s+1,s+n+1);
        int cnt=0;
        for(int i=1;i<=n;i++){
            while(i+1<=n && s[i]==s[i+1]) i++;
            p[++cnt]=s[i];
        }
        n=cnt;
        cnt=0;
        for(int i=1;i<=n;i++){
            for(int j=i+1;j<=n;j++){
                point a=p[i],b=p[j];
                if(dcmp(a.x-b.x)==0){
                    e[++cnt].k=INF*1.0;
                    e[cnt].b=a.x;
                } else {
                    e[++cnt].k=(a.y-b.y)/(a.x-b.x);
                    e[cnt].b=a.y-e[cnt].k*a.x;
                }
                e[cnt].A=i;
                e[cnt].B=j;
            }
        }
        sort(e+1,e+cnt+1);
        ll ANS=0;
        mst(q,0);
        for(int i=1;i<=cnt;i++){
            int l=i;
            while(dcmp(e[i].k-e[i+1].k)==0 && dcmp(e[i].b-e[i+1].b)==0 && i+1<=cnt){
                i++;
            }
            int ans=0;
            for(int j=l;j<=i;j++){
                if(q[e[j].A]==0){
                    ans+=mp[p[e[j].A]];
                    q[e[j].A]=1;
                }
                if(q[e[j].B]==0){
                    ans+=mp[p[e[j].B]];
                    q[e[j].B]=1;
                }
            }
            ANS=((ANS+Pow[ans]-1-ans)%mod+mod)%mod;
            for(int j=l;j<=i;j++){
                q[e[j].A]=0;
                q[e[j].B]=0;
            }
        }
        for(int i=1;i<=n;i++){
            int tot=0,Num=0;
            for(int j=1;j<=n;j++){
                if(i==j) continue;
                point a=p[i],b=p[j];
                if(dcmp(a.x-b.x)==0){
                    e[++tot].k=INF*1.0;
                    e[tot].b=a.x;
                } else {
                    e[++tot].k=(a.y-b.y)/(a.x-b.x);
                    e[tot].b=a.y-e[tot].k*a.x;
                }
            }
            sort(e+1,e+tot+1);
            for(int j=2;j<=tot;j++){
                if(dcmp(e[j].k-e[j-1].k)==0 && dcmp(e[j].b-e[j-1].b)==0) continue;
                Num++;
            }
            if (tot==0) ANS=(ANS+Pow[mp[p[i]]]-1-mp[p[i]])%mod;
            else if(Num==0) {
              ///  if(n>1) continue;
             ///   ANS=((ANS+Pow[mp[p[i]]]-1-mp[p[i]])%mod+mod)%mod;
            } else {
                ANS=((ANS-Num*(Pow[mp[p[i]]]-1-mp[p[i]])%mod+mod)%mod+mod)%mod;
            }
        }
        printf("%I64d\n",ANS);
    }
    return 0;
}
/*
10
5
1 0
2 0
3 0
4 0
5 0
3
1 1
1 1
1 1
3
0 0
0 1
1 0
1
0 0
7
2 5
4 4
4 4
2 2
2 2
2 2
4 1
9
2 5
2 5
4 4
4 4
4 4
4 1
2 2
2 2
2 2
*/




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值