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

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-23 05:01:27

Codeforces Gym 100492A(凸包,巧妙算法)的相关文章

Codeforces gym Hello 2015 Div1 B and Div2 D

Codeforces gym 100571 problem D Problem 给一个有向图G<V,E>和源点S,边的属性有长度L和颜色C,即E=<L,C>.进行Q次询问,每次给定一个点X,输出S到X的最短路的长度(不存在则输出 -1).但要求S到X的路径中相邻两条边颜色不一样. Limits Time Limit(ms): 1000 Memory Limit(MB): 256 |V|, |E|: [1, 10^5] X, S: [1, |V| ] L: [1, 10^9] |C|

求凸包—— graham_scan算法

求凸包—— graham_scan算法 先按Y-X排序,在按对p0的极角排序,然后进行扫描 Point stk[maxn]; int top; bool cmpYX(const Point A,const Point B)//按Y-X排序 { if(A.y<B.y) return true; if(A.y==B.y){ return A.x<=B.x; } return false; } bool cmp(const Point A,const Point B)//按极角排序 { return

Codeforces gym Hello 2015 Div1 E

Codeforces gym 100570 problem E (一种处理动态最长回文子串问题的方法) Problem 给一个长度为N的字符串S,字符集是'a'-'z'.进行Q次操作,操作分三种.一,修改位置X的字符为C:二,查询以P位置为中心的最长回文子串的长度,并输出:三,查询以P与P+1的中间位置为中心的最长回文子串的长度,并输出. More 第二种操作子串长度为奇数,一定存在:第三种操作子串长度为偶数,若不存在,输出 -1. Limits Time Limit(ms): 4000(1s足

Codeforces gym Hello 2015 Div1 C and Div2 E

Codeforces gym 100570 problem C Codeforces gym 100571 problem E Problem 给一个N行M列的矩阵Ma,进行Q次(Q<=10)查询,每次给定一个K,问有多少子矩阵,满足最大值max - 最小值min <=K. Limits Time Limit(ms): 8000 Memory Limit(MB): 512 N, M: [1, 400] Q: [1, 10] Ma(i, j), K: [1, 10^9] Solution (Th

【模拟】ECNA 2015 I What&#39;s on the Grille? (Codeforces GYM 100825)

题目链接: http://codeforces.com/gym/100825 题目大意: 栅栏密码.给定N(N<=10),密钥为一个N*N的矩阵,'.'代表空格可以看到,'X'代表被遮挡,还有密文字符串S,长度为N*N 每次将这个矩阵顺时针旋转90°,把矩阵中空格对应的位置按照从上到下从左到右的顺序依次填充上密文字符,求最终这个密文字符能否填满N*N的矩阵,能按顺序输出得到的答案,不能输出"invalid grille" 题目思路: [模拟] 直接模拟即可.旋转的坐标公式很好推.

Codeforces gym Hello 2015 Div2 B

Codeforces gym 100571 problem B Problem 设函数F(x),F(1)与F(2)已知,且当 i>=3,F(i)=a*F(i-2)+b*F(i-1).再给一个长度为N的数列A,进行Q次如下操作:每次给一个区间[L, R],对于每个k(L=<k<=R),将A[k]=A[k]+F[k-L+1].最后输出数列A(mod 10^9+7). Limits Time Limit(ms): 1000 Memory Limit(MB): 256 N, Q: [1, 10^

Codeforces Gym - 101147J Whistle&#39;s New Car

Discription Statements Whistle has bought a new car, which has an infinite fuel tank capacity. He discovered an irregular country since it has n cities and there are exactly n?-?1roads between them, of course, all cities are connected. He is so much

Codeforces Gym 101174 A Within Arm&#39;s Reach 贪心 手臂

#include<iostream> #include<stdio.h> #include <string.h> #include <algorithm> #include <vector> #include <math.h> using namespace std; #define LL long long const int maxn=25; double a[maxn],l[maxn],r[maxn]; double ex,ey

Codeforces Gym 100203G Good elements 暴力乱搞

原题链接:http://codeforces.com/gym/100203/attachments/download/1702/statements.pdf 题解 考虑暴力的复杂度是O(n^3),所以我们需要记录所有的ai+aj,如果当前考虑到了ak,那么就去前面寻找ai,使得ak-ai是我们记录过的和.整个算法的复杂度O(n^2). 代码 #include<iostream> #include<cstring> #include<cstdio> #include<