map+组合数学_____Eureka( POJ 5738 2016多校第二场)

roblem 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,vP,uv) are called best pair, if for every wPf(u,v)g(u,v,w), where f(u,v)=(xuxv)2+(yuyv)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 (1n1000) -- then number of points.

Each of the following n lines contains two integers xi and yi (109xi,yi109) -- 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
 
题意:

给定n个平面点,对于一个点集合P,存在一对点u,v.任意w∈P,u,v间的距离≥u,v,w,间距离和的一半。求这样的集合数量。



分析:

化简公式可知,当集合中的所有点共线的时候则集合满足题意。

用最简即约分数表示斜率然后用map存,然后就是组合数学的事情,注意,因为可能有多个点同坐标,所以要特殊处理!!!


代码:

#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<map>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
struct node
{
    ll x,y;
    node(){}
    node(ll a,ll b){ x = a, y = b;
    }
    bool operator < (node b) const
    {
        if( x == b.x) return y < b.y;
        return x < b.x;
    }
};
node p[1010];
map<node,ll> mpt;
int n;

ll gcd(ll a,ll b)
{
    return b == 0 ? a : gcd(b,a%b);
}
bool cmp(node a, node b)
{
    if(a.x == b.x)
        return a.y < b.y;
    return a.x < b.x;
}
ll pow2(ll a,ll b)
{
    if( b == 0) return 1;
    if( b == 1) return a%mod;
    if( b % 2 == 0) return pow2(a*a%mod,b/2);
    return pow2(a*a%mod,b/2)*a%mod;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        ll cnt = 0;
        scanf("%d",&n);
        for(int i = 0 ; i < n ; i ++)scanf("%lld%lld",&p[i].x,&p[i].y);
        sort(p,p+n);
        for(int i = 0 ; i < n ; i ++)
        {
            mpt.clear();
            ll step = 0;
            for(int j = i + 1 ; j < n ; j ++)
            {
                if(p[i].x == p[j].x && p[i].y == p[j].y)
                {
                    step ++;
                }
                else
                {
                    ll tx = p[j].x - p[i].x;
                    ll ty = p[j].y - p[i].y;
                    ll g = gcd(tx,ty);
                    if( g != 0)
                    {
                        mpt[node(tx/g,ty/g)] ++;
                    }
                }
            }
            if(step >= 1) cnt = (pow2(2,step)+cnt-1)%mod;
            for(map<node,ll>::iterator it = mpt.begin() ; it != mpt.end() ; it ++)
            {
                ll k = it->second;
                cnt = (cnt + (pow2(2,k)-1)* pow2(2,step))%mod;
            }
        }
        printf("%lld\n",cnt);
    }
    return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值