6603: ConvexScore
时间限制: 1 Sec 内存限制: 128 MB
提交: 87 解决: 43
[提交] [状态] [讨论版] [命题人:admin]
题目描述
You are given N points (xi,yi) located on a two-dimensional plane. Consider a subset S of the N points that forms a convex polygon. Here, we say a set of points S forms a convex polygon when there exists a convex polygon with a positive area that has the same set of vertices as S. All the interior angles of the polygon must be strictly less than 180°.
For example, in the figure above, {A,C,E} and {B,D,E} form convex polygons; {A,C,D,E}, {A,B,C,E}, {A,B,C}, {D,E} and {} do not.
For a given set S, let n be the number of the points among the N points that are inside the convex hull of S (including the boundary and vertices). Then, we will define the score of S as 2n−|S|.
Compute the scores of all possible sets S that form convex polygons, and find the sum of all those scores.
However, since the sum can be extremely large, print the sum modulo 998244353.
Constraints
1≤N≤200
0≤xi,yi<104(1≤i≤N)
If i≠j, xi≠xj or yi≠yj.
xi and yi are integers.
输入
The input is given from Standard Input in the following format:
N
x1 y1
x2 y2
:
xN yN
输出
Print the sum of all the scores modulo 998244353.
样例输入
4
0 0
0 1
1 0
1 1
样例输出
5
提示
We have five possible sets as S, four sets that form triangles and one set that forms a square. Each of them has a score of 20=1, so the answer is 5.
来源/分类
GPLv2 licensed by HUSTOJ 2018
小结:个人认为这个题是较好的,一种思维转换的能力是要慢慢加强的,思考问题的方式有很多,而总有一种是通往AC的最简洁道路。
题意:给定n个点,现在如果m个点能够构成一个凸包(注意:凸包是要求所有内角要严格小于180°的),现在设这个凸包里所有的点包括他的各个顶点m个共有sum个,那么一个凸包的贡献为2^(sum-m),求所有的总和,结果模除mod。
思路:想了一些时间,发现思路挺神奇的,切入正题
现在假设一个凸包它的点集即它的顶点有m个,那么它里面的点有k个,那么我们要求的贡献就是2^k个,这意味着对于里面的k个点,我们有2^k个子集就是有这么多不同的选择方式,现在明白的基础抛开上述,想如果一个凸包里面没有点!那么它的贡献就是2^0 = 1个,现在在想你抛开的那些,那2^k个实际上都包含了你所构成的凸包,所以问题就转化成给定n个点集问能够构成多少个不同的凸包,转到这一步就很好求了,n个点集共能构成2^n个不同集合,减去空集-1,减去一个点的集合-n,减去两个点的集合以及所有共线可能出现的情况就是最终答案
枚举任意两个点查找与这两个点共线的顶点有多少个那么他们构成的不成立的“凸包”就知道了
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define IO ios::sync_with_stdio(false),cin.tie(0)
#define FIN freopen("D://code//in.txt", "r", stdin)
#define ppr(i,x,n) for(int i = x;i <= n;i++)
#define rpp(i,n,x) for(int i = n;i >= x;i--)
const double eps = 1e-8;
const int mod = 998244353;
const int maxn = 1e6 + 7;
const double pi = acos(-1);
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
inline ll qow(ll a,ll b){ll r=1,t=a; while(b){if(b&1)r=(r*t)%mod;b>>=1;t=(t*t)%mod;}return r;}
inline int read() {//读入挂
int ret = 0, c, f = 1;
for(c = getchar(); !(isdigit(c) || c == '-'); c = getchar());
if(c == '-') f = -1, c = getchar();
for(; isdigit(c); c = getchar()) ret = ret * 10 + c - '0';
if(f < 0) ret = -ret;
return ret;
}
int x[maxn],y[maxn];
int main()
{
IO;
int n;
cin>>n;
ll ans = qow(2,n);
ans = ans - 1 -n;//减去空集的情况,减去选一个点的情况,这里也可以先减去选两个点的情况,下面要相应处理,也可以不减,在下面有详细说明
ppr(i,1,n)cin>>x[i]>>y[i];
ppr(i,1,n)
{
ppr(j,i+1,n)
{
int cnt = 0;
ppr(k,j+1,n)//枚举i,j两个点然后找到其共线的点的个数
{
if((x[i]-x[k])*(y[k]-y[j]) == (x[k]-x[j])*(y[i]-y[k]))
cnt++;
}
ans = (ans - qow(2,cnt) + mod)%mod;
/*改变就在这里如果不减去选择两个点的情况那么,在这里我们选择的共线的点应该是2^cnt,因为空集也可以,就是我们
说的选择两个点的情况,如果减去了那么这里要减去1*/
}
}
cout<<ans<<endl;
return 0;
}