1 条题解
-
0
1. Description
在一个 的正方形中,给定 个横,纵坐标均不相等的关键点。
现在有两个人从左下角 的位置出发,前往右上角 的位置,他们只会向上或者向右走,并且会让两人连线扫过的面积尽可能大。
现在要求求出一个点集 ,在两人的路径都经过这个点集中的点且 尽可能大的前提下,使得两人连线扫过的面积尽可能小。
2. Solution
由于两人只会向上或向右走,因此点集 中的点必须 坐标递增, 坐标递增,那么 的最大大小就是以 为下标, 为权值的 LIS 的长度,这可以使用一个 的算法求出,同时也可以求出一个 表示以 结尾的 LIS 的长度,这比较简单,就不细说了。
同时由于两人会让连线扫过的面积尽可能大,而两人一定会同时经过点集中的点,所以扫过的面积一定是若干个矩形的面积之和,这也是显然的。
因此我们得到了一个 的 DP 做法,将所有关键点按照 坐标从小到大排序之后,假定 表示点集以第 个点结尾的最小代价,那么 $f_{i}=\min_{j=1}^{i-1} f_j+(x_i-x_j)\times (y_i-y_j)$ 其中 需要满足 且 。
这个时间复杂度显然还不够优秀,因此我们考虑优化。
首先,由于 只能从 的 转移过来,所以我们将所有关键点按照 分层,转移只在层与层之间进行,那么显然的,同一层的关键点 递增而 递减,这十分好理解,因为如果在同一层中存在 使得 且 ,那么 , 显然不应该出现在这一层。
然后我们尝试证明,对于处于同一层的 如果都可以从上一层 转移过来,那么当 的时候,决策点递减,换句话说,如果假设 的最优决策点为 , 的最优决策点为 ,证明 。
由于 是 的最优决策点, 是 的最优决策点,那么就有:
$$f_{p}+(x_i-x_p)\times (y_i-y_p)<f_q+(x_i-x_q)\times (y_i-y_q)\\ f_{p}+(x_j-x_p)\times (y_j-y_p)>f_q+(x_j-x_q)\times (y_j-y_q)\\$$上下相加即有:
$$f_{p}+(x_i-x_p)\times (y_i-y_p)+f_q+(x_j-x_q)\times (y_j-y_q)<f_q+(x_i-x_q)\times (y_i-y_q)+f_{p}+(x_j-x_p)\times (y_j-y_p)\\$$也就是:
$$-x_iy_p-x_py_i-x_jy_q-x_qy_j<-x_iy_q-x_qy_i-x_jy_p-x_py_j$$整理两边则有:
由于 ,由同一层的关键点 递增而 递减可以得到 ,因为这个式子大于 ,而 与 的正负性不同,所以 ,由此得到 。
但是现在有一个问题,就是从 转移到 还要满足 且 ,这反映到上一层的点中相当于一个区间。
因为 递增,所以满足 的点一定是一个形如 的区间,同理因为 递减,所以满足 的点一定是一个形如 的区间,那么可以转移到 的 的区间就是 。
而当 增大的时候,整个区间整体右移,这显然是没有办法直接利用决策单调性写的,因为我们上面的证明基于:
处于同一层的 如果都可以从上一层 转移过来
所以我们需要让所有 相同的 放在一起,才可以利用决策单调性来写。
但是如果不做任何处理的话,时间复杂度就退化为 的了,这显然是无法接受的,因此要对 的转移区间进行分割,然后分别求解,由此,我们联想到了线段树分治,也就是将询问挂在线段树上,那么在同一个节点上的询问就可以利用决策单调性来写了,具体可以使用分治来解决。
时间复杂度为 ,显然是可以通过此题了。
3. Code
/*by qwer6*/ /*略去缺省源与快读快写*/ const int N=2e5+5,M=1e6+5; int n,m,len,tot; ll ans; int f[N]; pii a[N]; ll g[N]; vector<int>level[N]; struct Node{ int ls,rs; vector<int>q; void init(){ ls=rs=0; q.clear(); } }tree[N<<1]; #define mid (l+r>>1) int New(){ tree[++tot].init(); return tot; } void change(int &p,int l,int r,int L,int R,int v){ if(!p)p=New(); if(L<=l&&r<=R){ tree[p].q.push_back(v); return ; } if(mid>=L)change(tree[p].ls,l,mid,L,R,v); if(mid<R)change(tree[p].rs,mid+1,r,L,R,v); } void CDQ(int idx,int p,int l,int r,int L,int R){ if(l>r)return ; ll mi=8e18; int x=tree[p].q[mid],place; for(int i=L,y;i<=R;i++){ if(mi>cal(x,level[idx][i])){ mi=cal(x,level[idx][i]); place=i; } } tomin(g[x],mi); CDQ(idx,p,l,mid-1,place,R); CDQ(idx,p,mid+1,r,L,place); } void dfs(int idx,int p,int l,int r){ if(!p)return ; CDQ(idx,p,0,tree[p].q.size()-1,l,r); if(l==r)return ; dfs(idx,tree[p].ls,l,mid),dfs(idx,tree[p].rs,mid+1,r); } #undef mid int findL(int idx,int x){ int l=0,r=level[idx].size()-1,res=level[idx].size(); while(l<=r){ int mid=l+r>>1; if(a[level[idx][mid]].second<a[x].second){ res=mid; r=mid-1; }else l=mid+1; } return res; } int findR(int idx,int x){ int l=0,r=level[idx].size()-1,res=-1; while(l<=r){ int mid=l+r>>1; if(a[level[idx][mid]].first<a[x].first){ res=mid; l=mid+1; }else r=mid-1; } return res; } signed main(){ read(n),read(m); for(int i=1;i<=n;i++) read(a[i].first),read(a[i].second); sort(a+1,a+n+1); for(int i=1,p;i<=n;i++){ if(len==0||f[len]<a[i].second){ f[++len]=a[i].second; level[len].push_back(i); continue; } p=lower_bound(f+1,f+len+1,a[i].second)-f; f[p]=a[i].second,level[p].push_back(i); } memset(g,0x3f,sizeof(g)); for(int x:level[1])g[x]=1ll*a[x].first*a[x].second; for(int idx=2,rt,l,r,R;idx<=len;idx++){ rt=0,R=level[idx-1].size()-1,l=r=-1; for(int x:level[idx]){ while(l<R&&a[level[idx-1][l+1]].second>a[x].second)l++; while(r<R&&a[level[idx-1][r+1]].first<a[x].first)r++; change(rt,0,R,l+1,r,x); } dfs(idx-1,rt,0,R); } ans=8e18; for(int x:level[len]) tomin(ans,g[x]+1ll*(m-a[x].first)*(m-a[x].second)); write(ans); }
- 1
信息
- ID
- 6962
- 时间
- 2000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者