HDU 5738 Eureka

时限卡的好紧,G++ 3400ms过的,C++超时了。

双关键字排序,然后从左一个一个点看过去,假设第i个点必选,然后对i之后的点按照i这个点为原点进行极角排序,极角相同的排在一起(可以除gcd之后排序),然后统计一下即可。重点需要注意一下。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
typedef long long LL;
void File()
{
    freopen("D:\in.txt","r",stdin);
    freopen("D:\out.txt","w",stdout);
}

const int maxn=1000+10;
const LL mod=1e9+7;
LL h[maxn];
struct X { LL x,y; } p[maxn],t[maxn];
int T,n,num[maxn];

bool cmp( X a,X b)
{
    if(a.x==b.x) return a.y<b.y;
    return a.x<b.x;
}

LL gcd(LL a,LL b) { if(b==0) return a; return gcd(b,a%b); }

int main()
{
    h[0]=1; for(int i=1;i<=1000;i++) h[i]=(2*h[i-1])%mod;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=0;i<n;i++) scanf("%lld%lld",&p[i].x,&p[i].y);
        sort(p,p+n,cmp); p[n].x=p[n].y=(LL)0x7fffffff;
        for(int i=0;i<n;)
        {
            int f=i;
            for(;;f++) if(p[i].x!=p[f].x||p[i].y!=p[f].y) break;
            for(int j=i;j<f;j++) num[j]=f-i-(j-i); i=f;
        }
        LL ans=0;
        for(int i=0;i<n;i++)
        {
            ans=(ans+h[num[i]-1]-1)%mod;
            int sz=0;
            for(int j=i+num[i];j<n;j++)
            {
                t[sz].x=p[j].x-p[i].x,t[sz].y=p[j].y-p[i].y;
                LL GCD=gcd(abs(t[sz].x),abs(t[sz].y));
                t[sz].x=t[sz].x/GCD, t[sz].y=t[sz].y/GCD; sz++;
            }
            sort(t,t+sz,cmp); t[sz].x=t[sz].y=(LL)0x7FFFFFFF;
            int cnt=1;
            for(int j=0;j<sz;j++)
            {
                if(t[j].x==t[j+1].x&&t[j].y==t[j+1].y) cnt++;
                else ans=(ans+h[num[i]-1]*(h[cnt]-1)%mod)%mod,cnt=1;
            }
        }
        printf("%lld
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zufezzt/p/5698056.html