欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【省选模拟】多边形(凸包DP)

程序员文章站 2024-03-16 19:51:04
...

【省选模拟】多边形(凸包DP)

  • 钦定一个点为起点,令 fi,jf_{i,j} 表示凸包的最后两个点为 i,ji,j 的方案数。
    枚举 kk 转移到 fk,if_{k,i} 需要满足 pik\triangle pik 中没有点,按叉积预处理与原点形成的三角形包涵的点数后就可以 O(n4)O(n^4) 做,发现这个可以前缀和优化,按与 ii 形成的极角排序,那么对于 kk 合法的转移是一个前缀,双指针扫一遍,于是就可以做到 O(n3)O(n^3)
#include<bits/stdc++.h>
#define cs const
using namespace std;
int read(){
	int cnt = 0, f = 1; char ch = 0;
	while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1; }
	while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
	return cnt * f;
}
cs int N = 505;
cs int Mod = 1e9 + 7;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b; }
int mul(int a, int b){ return 1ll * a * b % Mod; }
int dec(int a, int b){ return a - b < 0 ? a - b + Mod : a - b; }
void Add(int &a, int b){ a = add(a, b); }
void Mul(int &a, int b){ a = mul(a, b); }
struct Pnt{
	int x, y; Pnt(int _x=0, int _y=0){ x = _x; y = _y; }
	Pnt operator + (cs Pnt &a){ return Pnt(x+a.x,y+a.y); }
	Pnt operator - (cs Pnt &a){ return Pnt(x-a.x,y-a.y); }
	int operator * (cs Pnt &a){ return x*a.y-y*a.x; }
}p[N];
bool cmp(Pnt a, Pnt b){ return a.y==b.y?a.x<b.x:a.y<b.y; }
int n, ps[N][N<<1];
int dp[N][N], Cons;
int Cross(int a, int b, int c){ return (p[a]-p[c])*(p[b]-p[c]); }
bool comp(int a, int b){ return Cross(a,b,Cons) > 0; } 
int main(){
	n = read();
	for(int i=1; i<=n; i++) p[i].x=read(), p[i].y=read();
	sort(p+1, p+n+1, cmp);
	for(int i=1; i<=n; i++){
		for(int j=1; j<=n; j++) ps[i][j]=j;
		ps[i][i]=1; Cons=i;
		sort(ps[i]+2, ps[i]+i+1, comp);
		sort(ps[i]+i+1, ps[i]+n+1, comp);
		for(int j=n+1; j<n+n; j++) ps[i][j] = ps[i][j-n+1];
	} 
	int ans = 0;
	for(int i=1; i<=n; i++){
		memset(dp,0,sizeof(dp));
		for(int j=i+1; j<=n; j++){
			static int ql[N],qr[N]; int tl=0, tr=0, nx=ps[i][j], p=0;
			for(int k=2; k<=n; k++) if(ps[nx][k]==i){ p=k; break; }
			for(int k=p; k<p+n; k++){
				if(Cross(ps[nx][k],i,nx)>0) qr[++tr]=ps[nx][k];
				else ql[++tl]=ps[nx][k];
			} 
			int sm=0, l=1, r=1;
			while(r<=tr){
				if(l>tl||Cross(qr[r],ql[l],nx)<0) 
				Add(dp[nx][qr[r]],sm), ++r;
				else Add(sm,dp[ql[l]][nx]), ++l;
			}
			int pre=0;
			while(tr){
				if(!pre||Cross(qr[tr],pre,i)>0)
				Add(dp[nx][qr[tr]],1), pre=qr[tr];
				else dp[nx][qr[tr]]=0; tr--;
			}
			for(int k=j+1; k<=n; k++) Add(ans,dp[nx][ps[i][k]]);
		}
	} cout<<ans; return 0;
}
相关标签: DP 凸包