版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hhhhhhxh/article/details/80918377
题意:给出n个点,每个集合中至少存在两个点,且他们都共线,问一共有多少个这样的集合。
对于在同一个位置上的k个点,在这个位置上能产生的集合数为
对于其他的点,遍历每个点,再遍历其他点,计算出斜率。对于每个相同的斜率,是在这个点位置上至少取一个点,再在其他点上至少取一个点。设这个点上有p个点,其他共有q个点对应于这个点能产生这个斜率,则此时
千万不要像我一样干这种对点去重对斜率不去重的傻事……
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair <ll, ll> Point;
const ll MOD = 1e9 + 7;
const ll INF = 1e11;
int T;
int n;
Point point[1010];
int cntp;
map <Point, bool> vis;
map <Point, int> cnt;
ll ans;
ll mypow[1010]; // 2^n
// map <double, bool> vis2; // 记录斜率是否存在
map <double, int> cntXielv;
double Xielv[1010];
int cntx;
void init_mypow() {
mypow[0] = 1;
for (int i = 1; i <= 1000; i++) {
mypow[i] = (mypow[i - 1] * 2) % MOD;
}
}
int main() {
init_mypow();
scanf("%d", &T);
while (T--) {
vis.clear();
cnt.clear();
ans = 0;
cntp = 0;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
ll x, y;
scanf("%lld %lld", &x, &y);
Point tp = make_pair(x, y);
if (vis[tp]) {
cnt[tp]++;
}
else {
point[++cntp] = tp;
vis[tp] = true;
cnt[tp] = 1;
}
}
// for (int i=1;i<=cntp;i++){
// printf("%lld %lld %d\n",point[i].first,point[i].second,cnt[point[i]]);
// }
// printf("cntp = %d\n", cntp);
for (int i = 1; i <= cntp; i++) {
ll cntP = cnt[point[i]];
cntx = 0; // 记录斜率的个数
cntXielv.clear();
// vis2.clear();
for (int j = i + 1; j <= cntp; j++) {
// if (i == j)
// continue;
if (point[i].first == point[j].first) {
Xielv[++cntx] = (double)INF;
cntXielv[Xielv[cntx]] += cnt[point[j]];
}
else {
double tx = (double)(point[i].second - point[j].second) / (point[i].first - point[j].first);
Xielv[++cntx] = tx;
cntXielv[Xielv[cntx]] += cnt[point[j]];
}
}
sort(Xielv + 1, Xielv + cntx + 1);
// 以上:把i这个点对应其他点的所有斜率求出+排序后放入Xielv[]中,记为Xielv[1-cntx]
for (int j = 1; j <= cntx; j++) {
ll cntQ = cntXielv[Xielv[j]];
// 统计斜率为Xielv[j]的点有多少个,记为cntq
while (Xielv[j + 1] == Xielv[j] && j + 1 <= cntx) {
j ++;
// cntQ += cntXielv[Xielv[j + 1]];
}
// printf("cntP = %d | cntQ = %d\n", cntP, cntQ);
ans = (ans + (mypow[cntP] - 1) * (mypow[cntQ] - 1) % MOD + MOD) % MOD;
}
}
// ans = ans / 2;
// 加上在同一个点上的点所构成的集合
for (int i = 1; i <= cntp; i++) {
ll tmp = cnt[point[i]];
// printf("point = %d %d\n",point[i].first,point[i].second);
// printf("cnt = %d\n",tmp);
ans = (ans + mypow[tmp] - tmp - 1 + MOD) % MOD;
}
ans = (ans + MOD) % MOD;
printf("%lld\n", ans);
}
}