多校hdu5738 寻找

  这道题前面给了两个公式,其实仔细分析一下,就会发现其实是给了你一堆点的坐标,然后让你求这些点有多少种组合可以形成共线的情况当两个点在一个坐标上时这两个点可以看做是不同的两个点,也就是说如果两个点在一个坐标上,这两个点也算共线我的这道题的解题思路就是先把每一个点的横坐标按从小到大排好序,然后从第一个点开始遍历,当遍历到一个点的时候,以这个点为起点,再向下遍历,记录这个起点和以后每个点的向量,把这个向量化简到最小,用一个map保存起来,最后通过总共有多少个向量数来计算有多少种共线。

  我们便利在当前点坐标要记住有多上重复的(用cnt),然后在遍历与这一点共线(线的数量sum)的每个点(除重复点的外),然后计算重复点能组成best对+与之共线的点(n)与使点构成的组合数=(2^cnt-n-1)+sum*((2^n-1)*(2^cnt-1)).

注意要用 1long long,2要在结果上mod;

以下是代码:

#include<map>
#include<stdio.h>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
#define  LL long long
#define N 1010
const int  mod =1e9+7;
map<pair<int ,int >, int> M;
map<pair<int,int>,int>::iterator it;//迭代器
LL n,cnt;
struct T
{
    LL x,y;
} point[N];
LL gcd(LL a,LL b)  //最大公约数
{
    return b==0?a:gcd(b,a%b);  
}
bool cmp(T a,T b)
{
    if(a.x==b.x)
        return a.y<b.y;
    return a.x<b.x;
}
LL sm(LL a, LL b)     //快速幂
{ LL ans
= 1; a = a%mod; while (b > 0) { if (b % 2 == 1) ans = (ans*a) % mod; b = b / 2; a = (a*a) % mod; } return ans; } int main() { LL t,i,j; LL ans; cin>>t; while(t--) { ans=0; scanf("%lld",&n); for(i=0; i<n; i++) { scanf("%lld%lld",&point[i].x,&point[i].y); } sort(point,point+n,cmp); for(i=0; i<n-1; i++) { M.clear(); cnt=1; for(j=i+1; j<n; j++) { LL x1=point[j].x-point[i].x; LL y1=point[j].y-point[i].y; if(!x1&&!y1) { cnt++; continue; } LL s=gcd(x1,y1); M[make_pair(x1/s,y1/s)]++; } if(cnt>1) { ans%=mod; ans+=sm(2,cnt)-1-cnt; } LL ans1=sm(2,cnt)-1; for(it=M.begin(); it!=M.end(); it++) { int h=it->second; ans+=(ans1*(sm(2,h)-1))%mod; } i+=cnt-1; } printf("%I64d\n",ans%mod); } return 0; }

 

 

 

posted on 2016-07-27 10:59  远搏  阅读(205)  评论(0编辑  收藏  举报

导航