Codeforces Gym 100492A(凸包,巧妙算法)

题意:给一个凸包,含有N个点,求删除每个点后再求凸包,凸包上的点的平均值。以p/q的最简形式输出,起初q=N。题目要求凸包不允许有两条相邻边平行。
链接:http://codeforces.com/gym/100492 A题

解法:咋一看没啥思路,可能会想到枚举删除每个点,其左边的点到右边的点再求一次凸包 这样的方法,虽然复杂度依然是O(N)的,但是这样编码起来极其困难,而且容易写挂。多想一想,发现只需求若干次凸包即可,正解如下。先求一次凸包,假设凸包上有偶数个点1..n,接下来,每两个点间接着屏蔽,先屏蔽凸包上1,3,5,… n-1号点,然后求一次凸包,此时表示1,3,5,… n-1号点被删除时候的情况,计算出答案之一,再屏蔽2,4,6,… n号点,再计算一次,除此之外,还要计算删除不在凸包上的点的情况。三次答案之和为最终答案。当凸包上的点为奇数时,需要多加一次计算,但做法类似。注意三或四次计算时的计算方法,不要统计少或多。

小结:此题属于方法好就好写,方法不好就很难写甚至“无法写“的题目,思维难度大,编码容易,多写此类型题有助于思维提高。

//Hello. I'm Peter.
//#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<cctype>
#include<ctime>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

const double eps = 1e-9, pi = acos(-1.0);

inline int dcmp(double x){
    if(fabs(x) < eps) return 0;
    else if(x > 0) return 1;
    else return -1;
}

struct Point{
    double x, y;
    int id;
    Point(){};
    Point(double x1, double y1){
        x = x1;
        y = y1;
    }
};
typedef Point Vector;

Vector operator - (const Vector a, const Vector b){
    return Vector(a.x - b.x, a.y - b.y);
}
double operator % (const Vector a, const Vector b){
    return a.x * b.y - a.y * b.x;
}
bool cmp1(const Point a, const Point b){
    if(dcmp(a.x - b.x) != 0) return a.x < b.x;
    else return a.y < b.y;
}

#define N 200010
int notvis[N],kase;

void ConvexHull(Point *p, int n, Point *c, int &m){
    m = 0;
    for(int i = 0; i < n; i++){
        if(notvis[p[i].id] == kase) continue;
        while(m > 1 && dcmp((c[m-1] - c[m-2]) % (p[i] - c[m-1])) <= 0) m--;
        c[m++] = p[i];
    }

    int k = m;
    for(int i = n - 2; i >= 0; i--){
        if(notvis[p[i].id] == kase) continue;
        while(m > k && dcmp((c[m-1] - c[m-2]) % (p[i] - c[m-1])) <= 0) m--;
        c[m++] = p[i];
    }

    if(m > 1) m--;
}
Point p[N], c[N], d[N];
int n, m, nd;

ll up, down;

int main(){
    freopen("average.in","r",stdin);
    freopen("average.out","w",stdout);

    n = read();
    for(int i = 0; i < n; i++){
        int x, y;
        x = read(), y = read();
        p[i] = Point(x, y);
        p[i].id = i;
        notvis[i] = 0;
    }
    sort(p, p + n, cmp1);

    kase = 1;
    ConvexHull(p, n, c, m);

    down = n;
    up = 1LL * (n - m) * m;

    if(m & 1){
        kase ++;
        for(int i = 0; i < m - 1; i += 2){
            notvis[c[i].id] = kase;
        }
        ConvexHull(p, n, d, nd);
        up += nd - ((m>>1) + 1) + 1LL * (m>>1) * (m - 1);

        kase ++;
        for(int i = 1; i < m - 1; i += 2){
            notvis[c[i].id] = kase;
        }
        ConvexHull(p, n, d, nd);
        up += nd - ((m>>1) + 1) + 1LL * (m>>1) * (m - 1);

        kase++;
        notvis[c[m-1].id] = kase;
        ConvexHull(p, n, d, nd);
        up += nd;
    }
    else{
        kase ++;
        for(int i = 0; i < m; i += 2){
            notvis[c[i].id] = kase;
        }
        ConvexHull(p, n, d, nd);
        up += nd - (m>>1) + 1LL * (m>>1) * (m - 1);

        kase ++;
        for(int i = 1; i < m; i += 2){
            notvis[c[i].id] = kase;
        }
        ConvexHull(p, n, d, nd);
        up += nd - (m>>1) + 1LL * (m>>1) * (m - 1);
    }

    ll g = __gcd(up, down);
    up /= g, down /= g;

    cout<<up<<"/"<<down<<endl;

    return 0;
}

你可能感兴趣的:(凸包)