题意

对于每一个凸多边形的顶点集S,定义其权值为2nS2^{|n|-|S|}
nn为凸包内的点集。求所有SS的权值和。

题解

栋老师模拟赛的题。。
之前用的是题解的方法
AtCoder Regular Contest 082 E - ConvexScore
这样就是O(n3)O(n^3),代码比较简单,这里就不放出来了

但是感觉这种凸包DP还是十分经典
不得不学一下
这题当然也是可以用凸包DP
普通的凸包DP是O(n4)O(n^4)
大概就是,我们先枚举凸包最下的一个点tmp\text tmp
然后像凸包一样排序
然后fi,jf_{i,j}表示最后两个点是i,ji,j的答案是多少
至于转移,就是找到一个点k,使得kktmptmp(i,j)(i,j)的同一个半平面内
也就是tmp,i,j,ktmp,i,j,k可以形成一个凸包
转移到fi,jf_{i,j}可以转移到fj,kf_{j,k}
直接这么做就是O(n4)O(n^4)的啦
你可以把这个过程想象成每一次加入一个三角形,不断把这个凸包拼出来
当然,你要预处理一个一下gi,jg_{i,j},表示tmp,i,jtmp,i,j这个三角形里面有多少个点
这个的话,你可以O(n4)O(n^4)预处理,也可以O(n3logn)O(n^3logn)预处理
我比较偷懒就写了O(n4)O(n^4)

再说一下这个凸包DP,看起来是O(n4)O(n^4)
但是可以观察到,如果我们先枚举j,然后把iikk按关于jj的极角排序
那么对于ii递增,kk都是连续的一段后缀
因此,排完序以后,可以单调地扫过去,就可以做到就可以省去一个nn
那么这个部分就是O(n3)O(n^3)
瓶颈在于排序O(n3logn)O(n^3logn),但是排序也可以预处理,那么凸包DP的整个过程就可以在O(n3)O(n^3)解决了
那么复杂度瓶颈就在于g了,然而我并不知道怎么优化这个g

下面给出代码(排序没有预处理的)
CODE:

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
const int MOD=998244353;
const int N=205;
int n;
struct qq
{
	int x,y;
	void print ()	{printf("%d %d\n",x,y);}
}a[N],b[N];
int tot;
int ans;
qq tmp;
int mul (qq x,qq y,qq z)
{
	int x1=x.x-z.x,y1=x.y-z.y;
    int x2=y.x-z.x,y2=y.y-z.y;
    return x1*y2-x2*y1;
}
int dis (qq x,qq y)	{return (x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y);}
bool cmp (qq x,qq y)
{
	if (mul(x,y,tmp)==0) return dis(x,tmp)<dis(y,tmp);
	return mul(x,y,tmp)>0;
}
bool cmp1 (int x,int y)
{
	if (mul(b[x],b[y],tmp)==0) return dis(b[x],tmp)<dis(b[y],tmp);
	return mul(b[x],b[y],tmp)>0;
}
bool check (qq x,qq y,qq z)//z是否在 (tmp,x,y)
{
	if (mul(z,x,tmp)==0) return false;
	if (mul(z,y,x)>0) return false;
	return true;
}
int f[N][N];
int g[N][N];
int mul (int x,int y)	{return (LL)x*y%MOD;}
int add (int x,int y)	{x=x+y;return x>=MOD?x-MOD:x;}
int id[N],id1[N];
int m,m1;
int Pow[N];
void solve (int x)
{
	//printf("solve:%d\n",x);
	tot=0;tmp=a[x];
	for (int u=1;u<=n;u++)
	{
		if (a[u].y>a[x].y||(a[u].y>=a[x].y&&a[u].x>=a[x].x))	b[++tot]=a[u];
	}
	sort(b+1,b+1+tot,cmp);
	for (int u=1;u<=tot;u++)	
		for (int i=1;i<=tot;i++)
			g[u][i]=f[u][i]=0;
	/*for (int u=1;u<=tot;u++)
		for (int i=u+1;i<=tot;i++)
		{
			int lalal=0;
			for (int k=u+1;k<i;k++)
			{
				if (mul(b[k],b[u],tmp)==0) continue;
				if (mul(b[k],b[i],b[u])<=0) lalal++;
			}
			g[u][i]=Pow[lalal];
		}*/
	for (int u=1;u<=tot;u++)
		for (int i=u+1;i<=tot;i++)
			g[u][i]=1;
	for (int u=1;u<=tot;u++)
		for (int k=u+1;k<=tot;k++)
		{
			if (mul(b[k],b[u],tmp)==0) continue;
			for (int i=k+1;i<=n;i++)
			{
				if (mul(b[k],b[i],b[u])<=0)
				g[u][i]=add(g[u][i],g[u][i]);
			}
		}
	for (int u=2;u<=tot;u++)
	{
		f[1][u]=1;
		for (int i=2;i<u;i++)
			if (mul(b[i],b[u],b[1])==0)
				f[1][u]=add(f[1][u],f[1][u]);
	}
	for (int i=2;i<=tot;i++)
	{
		//printf("i:%d\n",i);
		m=0;m1=0;
		for (int u=1;u<i;u++)	id[++m]=u;
		for (int u=i+1;u<=tot;u++) id1[++m1]=u;
		tmp=b[i];
		sort(id+1,id+1+m,cmp1);
		sort(id1+1,id1+1+m1,cmp1);
		int now=1,k=m1,sum=0;
		for (int u=1;u<=m1;u++)
		{
			while (now<=m&&mul(b[id1[u]],b[i],b[id[now]])<0)
			{
				sum=add(sum,f[id[now]][i]);
				now++;
			}
			f[i][id1[u]]=add(f[i][id1[u]],mul(sum,g[i][id1[u]]));
		}
	}
	for (int u=2;u<=tot;u++)
		for (int i=u+1;i<=tot;i++)
			ans=add(ans,f[u][i]);
}
int main()
{
	freopen("c.in","r",stdin);
	freopen("c.out","w",stdout);
	scanf("%d",&n);
	Pow[0]=1;for (int u=1;u<=n;u++) Pow[u]=add(Pow[u-1],Pow[u-1]);
	for (int u=1;u<=n;u++)	scanf("%d%d",&a[u].x,&a[u].y);
	for (int u=1;u<=n;u++) solve(u);
	printf("%d\n",ans);
	return 0;
}

相关文章:

  • 2021-08-15
  • 2022-03-02
  • 2022-02-26
  • 2021-06-15
  • 2021-08-04
  • 2021-07-06
  • 2021-07-12
  • 2021-12-02
猜你喜欢
  • 2021-07-21
  • 2022-01-04
  • 2021-10-03
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案