Something about 计算几何

没人做计算几何了,怎么会事呢...

这几把军训...laji时间找点laji题来做

一. 板子

1.basic

2.凸包

3.半平面交

二.板题

三.题目

P3194

给出\(N<50000\)条直线,找出从y正无穷大可见直线


手玩发现所有可见线段构成一个下凸壳。将所有直线按照斜率递增排序,用单调栈维护。栈顶为AB,插入C时,若AC交点在AB交点左侧或重合,则B无贡献。注意每种斜率的直线保留最上面的


for(int i=1;i<=n;++i) {
	if(l[i].k==l[i-1].k) continue;
	while(cnt>=2) {
		point A1=point(1,f(l[stk[cnt]],1)),A2=point(2,f(l[stk[cnt]],2));
		point B1=point(1,f(l[stk[cnt-1]],1)),B2=point(2,f(l[stk[cnt-1]],2));
		point C1=point(1,f(l[i],1)),C2=point(2,f(l[i],2));
		if(dcmp(LL(A1,A2,B1,B2).x-LL(C1,C2,A1,A2).x)>=0) {
			cnt--; 
		} else break;	
	}
	stk[++cnt]=i;
}

P2924

给出\(N<=250\)个点,保证不存在三点共线,求可以由这些点围成的凸包中,最多的点数


dp。注意到转移的斜率是单调的,把n方条边全部连上并按斜率排序作为转移。以每个点为起点dp一次,一定有一个点是转移首尾相连的位置。从起点扩张的正向边与回到起点的反向边的枚举顺序是相反的,不会造成影响


for(int i=1;i<=n;++i) {
	memset(f,-0x3f,sizeof(f));
	f[i]=0;
	for(int j=1;j<=cnt;++j) {
		f[e[j].r]=max(f[e[j].r],f[e[j].l]+1);
	}
	ans=max(ans,f[i]);
}

四.乱七八糟

P3299

僵尸排成一列进攻,僵尸间的距离相等,速度1m/s。第一行两个空格隔开的正整数\(N<100000\)和d,分别表示关数和相邻僵尸间的距离。

接下来n行每行两个空格隔开的正整数,分别表示相比上一关在僵尸队列排头增加血量为Ai 点的僵尸,排头僵尸从距离房子Xi米处开始接近。

每一关都可以用一个攻击力为\(y_i/s\)的植物来防御,植物一刻不停地攻击,求完成所有关卡最小的\(\sum y\)


考虑放到第m个时第i个僵尸被击败的条件,为\(x_m+x_{m-1}+...+x_i\le y(X+d(m-i))\),即\(y \ge \frac{sum_m-sum_{i-1}}{X+dm-di}\),可以把右式看作\((dm+X,sum_m)\)\((di,sum_{i-1})\)之间的斜率,相当于求某点到一些点斜率的最大值。可以维护所有\((di,sum_{i-1})\)构成的下凸壳,询问时在凸壳上二分。凸壳上点与某点连线的斜率是先增大后减小的。

非常好套路,但有凸壳就是计算几何吗...


//用这个dcmp,eps要取到1e-12才能过...
for(int i=1;i<=n;++i) {
	int x; point p;
	cin>>a[i]>>x; sum[i]=a[i]+sum[i-1];
	while(cnt&&rate(stk[cnt],point(i*d,sum[i-1]))<rate(stk[cnt],stk[cnt-1])) cnt--;
	stk[++cnt]=point(i*d,sum[i-1]);
	int l=1,r=cnt,nans=0; p=point(d*i+x,sum[i]);
	while(l<=r) {
		int mid=l+r>>1;
		if(dcmp(rate(p,stk[mid])-rate(p,stk[mid-1]))!=-1) nans=mid,l=mid+1;
		else r=mid-1;
	}
	ans+=rate(stk[nans],p); 
//	cout<<ans<<endl;
}
posted @ 2024-07-08 21:32  Kur0n1ko  阅读(12)  评论(0编辑  收藏  举报