题意
给出一些点,求有多少个集合满足在所有其他点都在其中两个点中间。
思路
首先题目给的那个式子化简之后就变成了求点共线的组合数的问题。
首先想到通过斜率统计然后否定了因为精度不行然后考虑把斜率表示成向量的形式,但是向量会有平行的情况也不好处理。然后用了这种固定一个点来求贡献的做法,不需要考虑平行也不需要考虑精度,唯一需要考虑的就是重点的问题了。单独考虑重点的时候集合就是
2num−1−1
个,重点和共线都计算在内的时候就是
(2num−1)∗(2cnt−1)
个。
代码
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
#define LL long long
#define Lowbit(x) ((x)&(-x))
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1|1
#define MP(a, b) make_pair(a, b)
const int INF = 0x3f3f3f3f;
const int MOD = 1000000007;
const int maxn = 1e5 + 10;
const double eps = 1e-8;
const double PI = acos(-1.0);
typedef pair<int, int> pii;
struct point
{
int x, y;
}p[1010];
bool cmp(point a, point b)
{
if (a.x == b.x) return a.x < b.x;
return a.y < b.y;
}
map<pii, int> vis;
int bit[1010];
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T, n;
scanf("%d", &T);
bit[0] = 1;
for (int i = 1; i <= 1000; i++)
bit[i] = (bit[i-1] * 2LL) % MOD;
while (T--)
{
scanf("%d", &n);
for (int i = 0; i < n; i++)
scanf("%d%d", &p[i].x, &p[i].y);
sort(p, p + n, cmp);
int ans = 0;
for (int i = 0; i < n; i++)
{
int mul = 1, ln = 0;
vis.clear();
for (int j = i + 1; j < n; j++)
{
if (p[i].x == p[j].x && p[i].y == p[j].y)
mul++;
else
{
int xx = p[i].x - p[j].x, yy = p[i].y - p[j].y;
int k = __gcd(xx, yy);
if (k != 0)
{
xx /= k;
yy /= k;
}
vis[MP(xx, yy)]++;
}
}
if (mul > 1)
ans = (ans + bit[mul-1] - 1) % MOD;
for (auto it : vis)
{
ln = it.second;
ans = (ans + (LL)bit[mul-1] * (bit[ln] - 1)) % MOD;
}
}
printf("%d\n", ans);
}
return 0;
}