把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【洛谷5939】[POI1998] 折线(坐标转化)

点此看题面

  • 规定二维平面上的一条折线只能从左向右一笔画过去,且每段与\(x\)轴的夹角在\([-45^\circ,45^\circ]\)范围内。
  • 给定\(n\)个点,求至少画多少条折线才能覆盖所有点。
  • \(n\le3\times10^4\)

坐标转化

考虑\((x_A,y_A)\)连向\((x_B,y_B)\)的折线(\(x_A<x_B\))与\(x\)轴夹角在\([-45^\circ,45^\circ]\)范围内的充要条件,转化成坐标关系就是:

\[-1\le \frac{y_B-y_A}{x_B-x_A}\le 1\Leftrightarrow\begin{cases}y_A+x_A\le y_B+x_B,\\y_A-x_A\ge y_B-x_B\end{cases} \]

于是我们把一个点的坐标转化为\((y+x,y-x)\),然后按首先第一维升序、其次第二维降序排序,问题就变成原序列至少需要拆成多少个单调不上升序列。

根据\(Dilworth\)定理,这个问题等价于求原序列的最长上升子序列长度。

代码:\(O(nlogn)\)

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 30000
using namespace std;
int n,f[N+5];struct P {int x,y;I bool operator < (Con P& o) Con {return x^o.x?x<o.x:y>o.y;}}p[N+5];
int main()
{
	RI i,x,y;for(scanf("%d",&n),i=1;i<=n;++i) scanf("%d%d",&x,&y),p[i]=(P){y+x,y-x};sort(p+1,p+n+1);//坐标转化+排序
	RI t=0;for(i=1;i<=n;++i) f[t&&p[i].y<=f[t]?lower_bound(f+1,f+t+1,p[i].y)-f:++t]=p[i].y;return printf("%d\n",t),0;//最长上升子序列
}
posted @ 2021-05-24 15:37  TheLostWeak  阅读(83)  评论(0编辑  收藏  举报