思路:
满足题意的点集为共线点集和相同点集,一个集合至少两个点;
无重复枚举每个点,找出相同点个数m,共线点个数
ki
(多条线),
包含此点的点集个数为
(2m−1−m)+sum((sm−1)∗(2k−1))
累加
#include <cstdio>
#include <cstring>
#include <map>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MOD = 1e9 + 7;
LL gcd(LL a, LL b)
{
if(!b)
return a;
return gcd(b, a%b);
}
struct point
{
int x, y;
friend bool operator==(const point &a, const point &b)
{
return a.x == b.x && a.y == b.y;
}
friend bool operator<(const point &a, const point &b)
{
if(a.x == b.x)
return a.y < b.y;
else
return a.x < b.x;
}
};
class line
{
LL a, b;
public:
line(point g, point h)
{
a = h.y - g.y;
b = g.x - h.x;
LL d = gcd(a, b);
a /= d;
b /= d;
if(a < 0)
{
a = -a;
b = -b;
}
}
friend bool operator<(const line &t, const line &t1)
{
if(t.a == t1.a)
return t.b < t1.b;
else
return t.a < t1.a;
}
};
point p[1010];
LL fp[1010];
void init()
{
fp[0] = 1;
for(int i = 1; i <= 1000; i++)
{
fp[i] = fp[i-1] << 1;
fp[i] %= MOD;
}
}
int main(int argc, char const *argv[])
{
init();
int t;
scanf("%d", &t);
while(t--)
{
int n;
scanf("%d", &n);
for(int i = 0; i < n; i++)
scanf("%d%d", &p[i].x, &p[i].y);
sort(p, p+n);
LL ans = 0;
for(int i = 0; i < n; i++)
{
int m = 1;
while(i+1 < n && p[i] == p[i+1])
{
m++;
i++;
}
ans += (fp[m] - 1 - m); //相同点集
ans %= MOD;
map<line, int> l;
l.clear();
for(int j = i+1; j < n; j++)
l[line(p[i], p[j])] ++;
for(map<line, int>::iterator it = l.begin(); it != l.end(); it++)
{
ans += (fp[m] - 1) * (fp[it->second] - 1); //共线点集
ans %= MOD;
}
}
printf("%d\n", ans);
}
return 0;
}