1 条题解
-
0
自动搬运
来自洛谷,原作者为

kczno1
**搬运于
2025-08-24 21:50:12,当前版本为作者最后更新于2017-02-26 08:34:11,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
根据角度离散线段端点。
而且射线必定经过某个线段端点,否则可以移动,且不会更差。
变成一些区间,选择一些点,使得涉及的区间最多,且没有区间被重复涉及。
也就是没有两个点在同一区间。
那么一个点i选择后,剩下的1->i的选择一定是一段前缀。而且是从i涉及的区间的最左端点left[i]的左边开始的。
f[i][j]表示前i个点选择了j个最多涉及的区间。
f[i][j]=max(f[i-1][j],f[left[i]-1][j-1]+num[i])
空间5*10^7个int是开不下的。
所以枚举j,再枚举i,之后可以在数组中删掉一维。
(一开始少打了个0,结果95)
#include<bits/stdc++.h> using std::sort; void chmax(int &x,int y) { if(x<y)x=y; } void chmin(int &x,int y) { if(x>y)x=y; } #define ll long long #define B 800005 #define N 2000010 struct point { int x,y; friend ll operator *(const point &x,const point &y) { return (ll)x.x*y.y-(ll)x.y*y.x; } }p0[N],*p[N]; int w[N];//离散后的位置 int t1; void ins(point *i) { scanf("%d%d",&i->x,&i->y); p[++t1]=i; } bool xiao(point *x,point *y)//y在x逆时针旋转方向 也就是x叉积y>0 { return (*x)*(*y)>0; } int top; int left[N],num[N],f[N]; int main() { freopen("1.in","r",stdin);freopen("1.out","w",stdout); int k,n,i;scanf("%d%d",&k,&n); for (i=1;i<=n;++i) { ins(p0+i);ins(p0+i+B); } sort(p+1,p+t1+1,xiao); top=1; int j=p[1]-p0; point now=p0[j]; w[j]=1; for (int i=2;i<=t1;++i) { int j=p[i]-p0; if (p0[j]*now) {now=p0[j];++top;} w[j]=top; } int x,y; for (i=1;i<=top;++i) left[i]=N; for (i=1;i<=n;++i) { if (w[i]>w[B+i]) {x=w[B+i];y=w[i];} else {x=w[i];y=w[B+i];} chmin(left[y],x);//chmin(left[x..y],x) 先更新最右的 最后从右往左更新一遍 ++num[x];--num[y+1];//[x,y]+1,差分 } for (i=1;i<=top;++i) num[i]+=num[i-1]; for (i=top-1;i>=1;--i) chmin(left[i],left[i+1]); while (k--) { for (i=top;i;--i) chmax(f[i],f[left[i]-1]+num[i]);//逆着来,此时f[left[i]-1]还是上一次的 for (i=1;i<=top;++i) chmax(f[i],f[i-1]);//顺着来,这样f[i-1]就是这一次的 } printf("%d",f[top]); }
- 1
信息
- ID
- 2635
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者