2016多校联赛2D Eureka(hdu 5738)

Eureka

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1638    Accepted Submission(s): 453


Problem 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  wP f(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
 

Author
zimpha
 

Source
 

Recommend
wange2014

题意:题目的公式化简之后就可以发现只要set里面的点全是共线的就是best set,然后,不难用数学推出只要统计出线上有多少个点,那么集合的数目可以求出来,题目还有重点的问题必须解决,所以还是很有难度的。经过围巾师兄的指点,我终于会做了这道题。下面给代码。
#include<iostream>
#include<stack>
#include<cstring>
#include<map>
#include<string>
#include<queue>
#include<algorithm>
#include<cstdio>
#include<utility>
using namespace std;
#define maxn 1005
#define MOD 1000000007
typedef long long LL;
struct node {
	int x, y;
}p[maxn];//储存点
int gcd(int a, int b) {
	if (!b)
		return a;
	else
		return gcd(b, a%b);
}
LL quitemod(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;
}
bool cmp(node a, node b) {
	return a.x < b.x || (a.x == b.x&&a.y < b.y);
}
int main() {
	int t;
	scanf("%d", &t);
	while (t--) {
		int n;
		scanf("%d", &n);
		for (int i = 1; i <= n; i++) {
			scanf("%d%d", &p[i].x, &p[i].y);
		}
		sort(p + 1, p + n + 1, cmp);
		LL sum = 0;//统计有多少个集合
		for (int i = 1; i <= n; i++) {
			map<pair<int, int>, LL>m;//储存一条线上有个点,pair储存斜率
			LL tj = 1;//统计重点
			for (int j = i + 1; j <= n; j++) {
				int fz = p[j].y - p[i].y;
				int fm = p[j].x - p[i].x;
				if (!fz&&!fm) {
					tj++;
					continue;
				}
				int x = gcd(fz, fm);
				if (x != 0) {
					fz /= x;
					fm /= x;
				}
				m[make_pair(fz, fm)]++;
			}
			if (tj > 1) {
				sum += quitemod(2, tj - 1) - 1;
				sum %= MOD;
			}
			map<pair<int, int>, LL>::iterator it;
			for (it = m.begin(); it != m.end(); it++) {
				sum = (sum + (quitemod(2, it->second) - 1) *quitemod(2, tj - 1) % MOD) % MOD;
			}
		}
		printf("%lld\n", sum);
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值