HDU 5738 Eureka 【共线点集】

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hhhhhhxh/article/details/80918377

题目链接

题意:给出n个点,每个集合中至少存在两个点,且他们都共线,问一共有多少个这样的集合。

对于在同一个位置上的k个点,在这个位置上能产生的集合数为 2 k k 1

对于其他的点,遍历每个点,再遍历其他点,计算出斜率。对于每个相同的斜率,是在这个点位置上至少取一个点,再在其他点上至少取一个点。设这个点上有p个点,其他共有q个点对应于这个点能产生这个斜率,则此时 a n s = a n s + ( 2 p 1 ) ( 2 q 1 )

千万不要像我一样干这种对点去重对斜率不去重的傻事……

#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);
    }
}

猜你喜欢

转载自blog.csdn.net/hhhhhhxh/article/details/80918377