简要题意

给定n个点,定义一个凸多边形包含点数s为:这个凸多边形覆盖的点数-这个凸多边形的角数(每一个角$<180°$)

设总点集为A。
这个凸多边形的分值为为:$2^s$

求由这n个点构成的所有凸多边形的分值和$mod 998244353$

简要题解

$2^s$是这s个点可选可不选的总方案数。
则答案是$\sum_{s\subset A}[s构成一个凸多边形]\sum_{t子集内的点被s多边形覆盖}1$

令$S=s\cup t$
我们可以直接枚举$S$。当$S$内的点不构成一条线段或只有一个点的时候,它有唯一的一个凸包,则它对答案的贡献就为1。

首先我们先不考虑线段,则答案为$2^n-n-1$(每个点选或不选-单点-空集)
接着我们找出每一条线段(点数$>1$),对于每条线段,假如有m个点,则它对答案的减少就为$2^m-m-1$(每个点选或不选-单点和空集没有之前已经去掉了)

简要代码

/*
Author: CNYALI_LK
LANG: C++
PROG: E.cpp
*/
#include<bits/stdc++.h>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define all(x) x.begin(),x.end()
using namespace std;
const double eps=1e-8;
const double PI=acos(-1.0);
typedef long long ll;
template<class T>void chkmin(T &a,T b){a=a<b?a:b;}
template<class T>void chkmax(T &a,T b){a=a>b?a:b;}
template<class T>T sqr(T a){return a*a;}
template<class T>T mmin(T a,T b){return a<b?a:b;}
template<class T>T mmax(T a,T b){return a>b?a:b;}
template<class T>T aabs(T a){return a<0?-a:a;}
#define min mmin
#define max mmax
#define abs aabs
const ll mod=998244353;
ll p[233];
struct zb{
    ll x,y;
};
zb a[233];
ll cmp(zb a,zb b){return a.x<b.x||a.x==b.x&&a.y<b.y;}
int main(){
#ifdef cnyali_lk
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
#endif
    ll n,ans;
    scanf("%lld",&n);
    p[0]=1;
    for(ll i=1;i<=n;++i){p[i]=p[i-1]<<1;if(p[i]>=mod)p[i]-=mod;scanf("%lld%lld",&a[i].x,&a[i].y);}
    sort(a+1,a+n+1,cmp);
    ans=p[n]-n-1;
    for(ll i=1;i<=n;++i)for(ll j=i+1;j<=n;++j){
        ll no=0;
        for(ll k=1;k<j;++k)if(k!=i&&(a[j].x-a[i].x)*(a[i].y-a[k].y)==(a[j].y-a[i].y)*(a[i].x-a[k].x)){no=1;break;}
        if(!no){
///         debug("(%lld,%lld) (%lld,%lld)",a[i].x,a[i].y,a[j].x,a[j].y);
            ll tot=2;
            for(ll k=j+1;k<=n;++k){
                if((a[j].x-a[i].x)*(a[i].y-a[k].y)==(a[j].y-a[i].y)*(a[i].x-a[k].x)){++tot;/*debug(" (%lld,%lld)",a[k].x,a[k].y);*/}
            }
//          debug("\n");
            ans-=p[tot]-tot-1;
        }
    }   
    printf("%lld\n",(ans%mod+mod)%mod);
    return 0;
}

标签: 计算几何

添加新评论