题目地址:http://exam.upc.edu.cn/problem.php?cid=1391&pid=0
题意:给N个点,有N的一个子集s组成的一个凸多边形,对于该凸多边形,它的边上是由s个点连接而成,
它的边上和内部共n个点,N中每个子集组成的凸多边形的贡献即是:2的n−|S|次幂。问对于这N个点来
说所有能组成凸多边形的子集的贡献和是多少。结果模除998244353。
参考了别的题解而来
分析:对于一个子集组成的凸多边形,n-s即是内部的点的个数,因此2的(n-s)次幂,即是表示凸多边形
内部的点取(为1)或者不取(为0)两种情况,因为它边上的n个点的个数是固定不变的,所以问题就转化为
对于一个子集n,其固定s个点和其内部的点一共可以组成多少个凸多边形,对于这N个点来说,问题就是可
以形成多少个凸多边形。 比起查找可以形成多少个凸多边形,更简单的是可以用总的情况数减去不满足的个数。
不满足的情况有:全部不取的----1
只取一个的-----n
只取两个的-----n*(n-1)/2
共线的
共线的求法就是枚举:
枚举两个顶点,看有多少个点在这两个顶点连成的线上。枚举的两个点固定,其他所有点遍历,情况数就是这条线上共线的点集个数。显然,不会有重复。累和,即为最终答案。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long ll;
#define mod 998244353
ll x[100010], y[100010], maze[100010];
int main() {
ll n;
scanf("%lld", &n);
for (int i = 0; i<n; ++i)
scanf("%lld%lld",&x[i],&y[i]);
maze[0] = 1;
for (int i = 1; i <= n; ++i)
maze[i]=(maze[i-1]*2)%mod;
ll sum= maze[n] - 1 - n - n*(n-1)/2;
for (int i = 0; i < n; i++){
for (int j = i+1; j < n; j++) {
int countt = 0;
for (int k = j+1; k < n; k++) {
if ((x[j]-x[i]) * (y[k]-y[j]) == (x[k]-x[j]) * (y[j]-y[i]))
countt++;
}
sum=(sum-(maze[countt]-1)+mod)%mod;
}
}
printf("%lld\n", sum);
return 0;
}