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;
}