ARC082E ConvexScore(神奇思路)

这题就是拼拼凑凑就出来了。

可能看英文题面容易题意杀(小写大写 (n,N)),这里复述一遍:对于每个构成凸多边形的点集(每个点恰好都是凸多边形的顶点,必须是严格的凸多边形,内角严格小于 180 度),贡献是 (2^{内部点个数})。内部点包括边,不包括顶点。求贡献之和。

(2^{内部点个数}) 很容易想到枚举内部点集合的子集。

然后发现就变成了:对于每个点集(这次不一定要构成凸多边形了),如果有凸包就有 (1) 的贡献。(感受一下)

可以用总方案数减掉不合法的方案数。不合法的点集一定是全部共线。

然后这个应该可以简单做了。把每两个点的直线拎出来,通过每一种线的出现次数算出这条线上的点数。

数据范围为啥是 200,死都不会 (O(n^3)),只会 (O(n^2log n))……

#include<bits/stdc++.h>
using namespace std;
const int maxn=222,mod=998244353;
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define ROF(i,a,b) for(int i=(a);i>=(b);i--)
#define MEM(x,v) memset(x,v,sizeof(x))
inline int read(){
	int x=0,f=0;char ch=getchar();
	while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
	return f?-x:x;
}
struct line{
	double k,b;
	bool operator<(const line &l)const{
		if(fabs(k-l.k)>1e-8) return k<l.k;
		return b<l.b;
	}
}l[25555];
int n,ans,pt[maxn],x[maxn],y[maxn],llen,cnt[25555];
inline int gcd(int x,int y){return y?gcd(y,x%y):x;}
int main(){
	n=read();
	FOR(i,1,n) x[i]=read(),y[i]=read();
	pt[0]=1;
	FOR(i,1,n) pt[i]=2*pt[i-1]%mod;
	ans=(pt[n]-(n+1)+mod)%mod;
	FOR(i,1,n) FOR(j,i+1,n){
		double k,b;
		if(x[i]==x[j]) k=1e9,b=x[i];
		else k=1.0*(y[j]-y[i])/(x[j]-x[i]),b=y[i]-k*x[i];
		l[++llen]=(line){k,b};
	}
	sort(l+1,l+llen+1);
	FOR(i,2,n) cnt[i*(i-1)/2]=i;
	FOR(i,1,llen){
		int j=i;
		while(j<=llen && fabs(l[i].k-l[j].k)<1e-8 && fabs(l[i].b-l[j].b)<1e-8) j++;
		j--;
		int x=cnt[j-i+1];
		ans=(ans-(pt[x]-(x+1)+mod)%mod+mod)%mod;
		i=j;
	}
	printf("%d
",ans);
}
原文地址:https://www.cnblogs.com/1000Suns/p/11737526.html