【AT3526】[ARC082C] ConvexScore(贡献转化+容斥)

点此看题面

  • 给定平面上(n)个点,如果一个大小为(c)的点集恰好构成凸包,假设这个凸包共包含(s)个点,则能产生(2^{s-c})的贡献。求总贡献。
  • (nle200)

贡献转化

考虑(2^{s-c})是个什么东西,发现就意味着构成凸包的这(c)个点必选,剩下的(s-c)个点可选可不选。

于是限制就从原本恰好构成凸包变成能够构成凸包,且每个能够构成凸包的点集贡献都是(1)

简单容斥

我们用点集总数(2^n)减去选择点数小于等于(2)的方案数(C_n^0+C_n^1+C_n^2),再减去选择大于等于(3)个点且这些点共线的方案数。

考虑枚举这些点中编号最小的两个(p_i,p_j),枚举之后每个点假设有(w)个与它们贡献,那么产生的非法方案数对应的就应该是(2^w-1),从总答案中减去即可。

代码:(O(n^3))

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 200
#define X 998244353
using namespace std;
int n;struct P {int x,y;}p[N+5];I int gcd(CI x,CI y) {return y?gcd(y,x%y):x;}
int main()
{
	RI i,j,k;for(scanf("%d",&n),i=1;i<=n;++i) scanf("%d%d",&p[i].x,&p[i].y);
	RI s=1;for(i=1;i<=n;++i) s=2LL*s%X;s=((s-1-n-1LL*n*(n-1)/2)%X+X)%X;//总方案数减去选择点数≤2的方案数
	RI t,g,tx,ty,kx,ky;for(i=1;i<=n;++i) for(j=i+1;j<=n;++j)//枚举编号最小的两个点
	{
		if(p[j].x==p[i].x) {for(t=1,k=j+1;k<=n;++k) p[k].x==p[i].x&&(t=2LL*t%X);goto End;} //x坐标相同
		if(p[j].y==p[i].y) {for(t=1,k=j+1;k<=n;++k) p[k].y==p[i].y&&(t=2LL*t%X);goto End;}//y坐标相同
		for(g=gcd(p[j].x-p[i].x,p[j].y-p[i].y),tx=(p[j].x-p[i].x)/g,ty=(p[j].y-p[i].y)/g,t=1,k=j+1;k<=n;++k)//一般情况
			!((p[k].x-p[i].x)%tx)&&!((p[k].y-p[i].y)%ty)&&(p[k].x-p[i].x)/tx==(p[k].y-p[i].y)/ty&&(t=2LL*t%X);
		End:s=(s-(t-1)+X)%X;//减去非法情况数
	}return printf("%d
",s),0;
}
败得义无反顾,弱得一无是处
原文地址:https://www.cnblogs.com/chenxiaoran666/p/AT3526.html