HDU5738

题意就是要找一条直线上的点,注意有重点;

组合数公式从0取到n为2n,注意运用就好

C(0,N)+C(1,N)+....+C(N,N)=2N

C(R,N)+C(R+1,N)=C(R+1,N+1)

数点的时候每个点有两种情况(出现,不出现),如果与第i个点相同的有m个,那么对于只有相同点时,ans=pqow(2,m)-1【减去都消失的情况】;一次共线的有n个,ans =pqow(2,m)*(pqow(2,n)-1)。 

注意运用第一个公式,因为第i个点必定要用到,其他的点用法有两种,只用i的重点和不止用i的重点

只用i的重点相当于从1开始取组合数

不止用i的重点则重点可以从0开始取组合数,非重点则从1开始取

#include <stdio.h>
#include<algorithm>
#include<string.h>
#include<iostream>
#include<map>
using namespace std;
typedef long long LL;
map<pair<LL,LL>,int>vis;
const int mod=1e9+7;
int t,n;
struct st{
LL x,y;
}num[1005];
bool cmp(st a,st b){
if(a.x==b.x)
    return a.y<b.y;
else
    return a.x<b.x;
}
LL gcd(LL a,LL b){
return b?gcd(b,a%b):a;
}

LL qpow(LL a,LL b){
    if(b<0)
        return 0;
    a%=mod;
    LL ans = 1;
    while(b) {
        if(b&1) ans = (ans * a) % mod;
        b >>= 1;
        a = (a * a) % mod;
    }
    return ans;
  }


int main()
{
    freopen("in.txt","r",stdin);
 cin>>t;
 while(t--){

    scanf("%d",&n);
    int i,j;
    for( i=1; i<=n; i++)
        scanf("%lld%lld",&num[i].x,&num[i].y);
    sort(num+1,num+1+n,cmp);
    LL ans=0;
    for( i=1; i<=n; i++){
        vis.clear();
        int res=1;
        for( j=i+1; j<=n; j++){
        if(num[j].x==num[i].x&&num[i].y==num[j].y)
            res++;
        else{
        LL dx=num[i].x-num[j].x;
        LL dy=num[i].y-num[j].y;
        LL gg=gcd(dx,dy);
        if(gg!=0){
            dx/=gg;
            dy/=gg;
        }
    
        vis[make_pair(dx,dy)]++;
        }
        }
        if(res>1){
        ans+=(qpow(2,res-1)-1)%mod;//第一种只用这个点的情况,用到当前遍历的点和与其重合的点
        ans%=mod;
        }
     // cout<<ans<<" "<<i<<endl;


            for(map<pair<LL,LL>,int>::iterator it = vis.begin();it!=vis.end();it++)
            {
                LL cnt=(it->second);
                ans = (ans+((qpow(2,cnt)-1)*(qpow(2,res-1)))%mod)%mod;//用重点和其他点的情况
            }


    }
    cout<<ans<<endl;
 }
}

 

posted @ 2016-07-23 13:53  十目  阅读(326)  评论(2编辑  收藏  举报