HDU5738 Eureka

題目連接:http://acm.hdu.edu.cn/showproblem.php?pid=5738


【題意】給定n個平面點,對於一個點集合P,存在一對點u,v.任意w∈P,u,v間的距離≥u,v,w,間距離和的一半。求這樣的集合數量。


【分析】由於三角形兩邊之和一定大於第三邊,那麼只有在三點共線的情況下等式成立,而不等式則恆不成立。於是轉換成共線點數目的組合數問題。需要注意的是會出現重點,重點需要額外處理。對輸入的點進行判別,僅保存不同的點,同時保存這個點的數量。枚舉每個點對其他點進行連接(注意j從i+1開始,避免重複),求出直線方程中的a和b。由於是同一個點出發,a,b確定k,k相同那麼c一定相同,根據a,b累計直線上點的數目。對枚舉的每個點,連接結束後計算直線上點數目形成的方案數。需要注意的是枚舉的點是所有直線的交點,這個點如果是重點的話,每條直線計算方案數時會重複計算,需要在開始就計算重點的方案數,每條直線的方案數要減去該重點方案數。同時,還要減去不使用枚舉點的方案數,避免後面枚舉時重複計算。


【代碼】

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
using namespace std;
#define LL long long
const int mod=1e9+7;
int c[1010][1010];
int sum[1010];
int NN[1000010];
int num[100100];

struct Node
{
    int x,y;
}node[1010];

bool operator<(Node n1,Node n2)
{
    if(n1.x!=n2.x)
        return n1.x<n2.x;
    return n1.y<n2.y;
}

int gcd(int a,int b){
    if(a==0 || b==0)
        return 1;
    if(a%b==0)
        return b;
    return gcd(b,a%b);
}

void init()
{
    sum[1]=0;
    for(int i=2;i<=1000;++i)
        sum[i]=(2*sum[i-1]+i-1)%mod;
}

int main()
{
    init();
    int t,n,x,y,a,b,c;
    double slo;
    scanf("%d",&t);
    while(t--)
    {
        map<Node,int> mp;
        memset(num,0,sizeof(num));
        int cnt=1;
        Node tmp;
        scanf("%d",&n);
        for(int i=0;i<n;i++){
            scanf("%d %d",&x,&y);
            tmp.x=x;
            tmp.y=y;
            if(mp[tmp]==0){
                num[cnt]++;
                node[cnt]=tmp;
                mp[tmp]=cnt++;
            }
            else
                num[mp[tmp]]++;
        }        
        int ans=0;
        for(int i=1;i<cnt;i++)
        {
            ans=(ans+sum[num[i]])%mod;
            map<Node,int> slope;
            for(int j=i+1;j<cnt;j++)
            {
                a=node[i].x-node[j].x;
                b=node[i].y-node[j].y;
                if(a<0){
                    a=-a;
                    b=-b;
                }
                if(a==0)
                    b=1;
                if(b==0)
                    a=1;
                c=gcd(abs(a),abs(b));
                a/=c;
                b/=c;
                tmp.x=a;
                tmp.y=b;
                slope[tmp]+=num[j];
            }
            for(map<Node,int>::iterator it=slope.begin();it!=slope.end();++it)
                ans=(((ans+sum[it->second+num[i]])%mod-sum[it->second])%mod-sum[num[i]])%mod;
        }
        ans=(ans+mod)%mod;
        printf("%d\n",ans);
    }
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章