题意:每个点两两连线,线的交点可以继续连线,给n个点,求其所有子点集不能无限画线的方法。
大致思路:在纸上画画,大概可以分成以下几种情况
- 4个点及以下
- 5点及以上共线
- 4点及以上共线 + 线外一点
- 3点及以上共线 + 线两侧各取一点
#include<bits/stdc++.h>
using namespace std;
using namespace std;
const int MAXN = 1111;
const int mod = 1e9 + 7;
const int inv2 = 5e8 + 4;
typedef long long ll;
struct point {
ll x, y;
double a;
point (ll x = 0, ll y = 0) :x(x), y(y), a(atan2(y, x)) {}
bool operator < (const point &rhs) const {
return a < rhs.a;
}
}p[MAXN << 1];
ll dot(point a, point b) {
return a.x * b.x + a.y * b.y;
}
ll cross(point a, point b) {
return a.x * b.y - a.y * b.x;
}
ll C[MAXN][MAXN], CC[MAXN][MAXN], dia[MAXN];
int x[MAXN], y[MAXN];
int icase, t, n, ans;
void init() {
CC[0][0] = C[0][0] = 1;
for (int i = 1; i < MAXN; i++)
for (int j = 0; j <= i; j++)
if (j == 0) CC[i][j] = C[i][j] = 1;
else {
C[i][j] = (C[i - 1][j] + C[i- 1][j - 1]) % mod;
CC[i][j] = (C[i][j] + CC[i][j - 1]) % mod;
}
}
void solve(int id) {
ll m = 0, d = 0, sum = 0;
for (int i = 0; i < n; i++) if (i != id) p[m++] = point(x[i] - x[id], y[i] - y[id]);
sort(p, p + m);
for (int i = 0; i < m; i++) p[i + m] = p[i];
for (int i = 0, j = 0, k = 0; i < m; i = j) {
while (j < i + m && cross(p[i], p[j]) == 0 && dot(p[i], p[j]) > 0) j++;
if (j > k) k = j;
while (k < i + m && cross(p[i], p[k]) > 0) k++;
if (k < i + m && cross(p[i], p[k]) == 0) {
if (i > k % m) continue;
int cnt = 0;
while (k < i + m && cross(p[i], p[k]) == 0) ++k, ++cnt;
dia[d++] = 1ll * cnt * (j - i) % mod;
sum = (sum + dia[d - 1]) % mod;
}
else {
int cnt = j - i + 1, l = k - j, r = i + m - k;
if (cnt >= 3) ans = (ans + 1ll * (CC[cnt][cnt] - CC[cnt][2] + mod) % mod * l % mod * r % mod) % mod;
if (cnt >= 4) ans = (ans + 1ll * (CC[cnt][cnt] - CC[cnt][3] + mod) % mod * (l + r) % mod) % mod;
if (cnt >= 5) ans = (ans + (CC[cnt][cnt] - CC[cnt][4] + mod) % mod) % mod;
}
}
for (int i = 0; i < d; i++) ans = (ans + mod - 1ll * dia[i] * (sum + mod - dia[i]) % mod) % mod;
}
int main() {
init();
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
for (int i = 0; i < n; i++) scanf("%d%d", x + i, y + i);
ans = 0;
for (int i = 0; i < n; i++) solve(i);
ans = 1ll * ans * inv2 % mod;
for (int i = 1; i <= 4; i++) ans = (ans + C[n][i]) % mod;
printf("Case #%d: %lld\n", ++icase, ans);
}
}