2015 浙江省赛C zoj3871 Convex Hull

博客介绍了ACM竞赛中的一道题目,要求计算平面上多个点的所有可能子集的凸包面积之和,且至少包含三个点。解答方法是通过计算每条边对原点的有向面积并乘以该边出现的次数,最后对结果取模998244353。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

<span style="font-family: Arial, Helvetica, Verdana, sans-serif; background-color: rgb(255, 255, 255);"></span>

Edward has n points on the plane. He picks a subset of points (at least three points), and defines the beauty of the subset as twice the area of corresponding convex hull. Edward wants to know summation of the beauty of all possible subsets of points (at least three points).

No two points coincide and no three points are on the same line.

Input

There are multiple test cases. The first line of input contains an integer T indicating the number of test cases. For each test case:

The first line contains an integer n (3 ≤ n ≤ 1000). Each of following n lines contains 2 integers xiyi which denotes a point (xiyi) (0 ≤ |xi|, |yi| ≤ 109).

The sum of values n for all the test cases does not exceed 5000.

Output

For each case, if the answer is S, output a single integer denotes S modulo 998244353.

Sample Input
1
3
0 0
0 1
1 0
Sample Output

1

题意:给定一个点数集合,问所有子集的凸包的面积和的两倍。

做法:关于凸包面积的一种经典算法就是求每条边到原点的有向面积和。这里就可以直接枚举每条边作为凸包上的边,求有向面积乘以出现次数即可。


#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdio>
using namespace std;
#define maxn 1001
#define LL long long
#define MOD 998244353
struct node{
    LL x,y;
    double ang;
    node(LL a=0,LL b=0):x(a),y(b){}
    node operator - (node a){return node(x-a.x,y-a.y); }
    LL operator ^ (node a){return x*a.y-a.x*y; }
    bool operator < (const node &a)const{  return ang<a.ang;   }
    void in(){scanf("%lld%lld",&x,&y); }
    void out(){printf("%lld %lld\n",x,y); }
}p[maxn*2],s[maxn];
int n;
LL ex2[maxn];
double PI =acos(-1.0);
void init(){
    for(int i=ex2[0]=1;i<maxn;i++)
        ex2[i]=(ex2[i-1]*2)%MOD;
}
LL solve(int x){
    swap(p[x],p[0]);
    for(int i=1;i<n;i++) p[i].ang=atan2(p[i].y-p[0].y,p[i].x-p[0].x);
    sort(p+1,p+n);
    for(int i=1;i<n;i++){
        p[n+i-1]=p[i];
        p[n+i-1].ang+=2.0*PI;
    }
    LL res=0;
    for(int i=1,j=1;i<n;i++){
        while(p[j].ang<p[i].ang+PI)j++;
        LL tmp=(ex2[j-i-1]-1)*(((p[0]^p[i])%MOD+MOD)%MOD)%MOD;
        res=(res+tmp)%MOD;
    }
    return res%MOD;
}
int main(){
    init();
    int T;scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(int i=0;i<n;i++){
            p[i].in();
            s[i]=p[i];
        }
        LL ans=0;
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++) p[j]=s[j];
            ans=(ans+solve(i))%MOD;
        }
        printf("%lld\n",ans);
    }
    return 0;
}




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值