题意:一个国王,他的城市对齐的建在两根平行的线上。城市有编号1-n(两边一样)。
输入:每次先输入一个数n,代表两边均有n个城市,接下来n行,每行两个整数a,b,表示A线上的城市a和B线上的城市b之间有一条马路。这样,马路之间便很有可能出现交点,国王要求你去除一些马路,使得最终留下的马路两两之间没有交点,并在此前提下尽量多的留下马路。
输出:最多留下的马路的数量。
题解:最长递增子序列
很典型,自己开始想只想到了dp,却没想到用二分,或者说,重点是没有想到用一个B[n]数组作为辅佐,来记录序列长度为k的序列中,最小序列尾的值B[k]。这个辅佐数组非常重要,因为它有单调递增的性质(因为如果有B[3]>B[4],那么在得到B[4]的序列中的第三个数B[4]3也会小于B[4]并且小于B[3],即有B[4]3<B[4]<B[3],这有与B数组的定义相悖),因为这个性质我们可以使用二分来进行查找,而且我们每次对于这个数组的修改插入只需在原数组上修改或在数组末尾增添,而这些都是o(1)的。
关于二分,做此题也算是复习了一下。二分总得来说就是通过每次刷选一半的区间,让区间左右两端的值都逼近目标值。
然后题目的输出格式要注意,有road(s)的区别。
以下为代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=5e5+10;
int num[maxn],B[maxn];
int len;
int find_pos(int a,int l,int r){
while(l<=r){
int mid=(l+r)/2;
if(B[mid]>a){
r=mid-1;
}
else l=mid+1;
}
if(l>len) len=l;
return l;
}
int main(){
int n;
int x,y;
int icount=1;
while(scanf("%d",&n)!=EOF){
len=1;
for(int i=0;i<n;++i){
scanf("%d%d",&x,&y);
num[x]=y;
}
B[1]=num[1];
for(int i=2;i<=n;++i){
int y=num[i];
B[find_pos(y,1,len)]=y;
}
if(len==1)
printf("Case %d:\nMy king, at most 1 road can be built.\n\n",icount++);
else printf("Case %d:\nMy king, at most %d roads can be built.\n\n",icount++,len);
}
return 0;
}