题意:
求最长上升子序列,但这个要用二分法:
博客参考:https://blog.csdn.net/idealistic/article/details/52181408
#include<iostream>
using namespace std;
long d[500001],a[500001]; //d[i]用来存最长不降子序列 最后一个元素
long find(long a,long left,long right) //二分查找
{
long mid;
while(left<=right)
{
mid=(left+right)/2;
if(a>d[mid])//偏小
left=mid+1;
else
right=mid-1;
}
return left;
}
int main()
{
long n,i,j,len,p,t,k=0;
while(scanf("%d",&n)!=EOF)
{
k++;
for(i=1;i<=n;i++)
{scanf("%d%d",&j,&p);
a[j]=p;}
d[1]=a[1];
len=1;//初始序列长度
for(i=2;i<=n;i++)
{
t=find(a[i],1,len); //找出a[i]的位置
d[t]=a[i]; //更新d[t],使d[t]尽量是最小的,显而易见,dp[t]越小,后面的dp[k](k>t)更大的可能性就会越大
//为什么可以这样做?仔细观察,发现对于一个a[i],要判断它是否是某个不降子序列的元素,我们只需要拿它和前面的dp[j](j<len)比较即可,
//由于dp[j]记录的是到a[j]为止的序列的最长不降子序列的最后一个元素,如果a[i]>dp[j]并且a[i].b<dp[j+1],
//那么我们自然要用a[i]更新dp[j+1](很明显,最长子序列长度为j+1),而如果a[i]比dp[j]的值都大,
//这说明a[i]可以接在所有的dp[j]后面,自然我们选择最长的dp[len],因此,加入之后,len的长度要自加1
if(t>len) //因为d[len]都是最大的
len++;
}
if(len==1)
printf("Case %d:\nMy king, at most %d road can be built.\n\n",k,len); //单数
else
printf("Case %d:\nMy king, at most %d roads can be built.\n\n",k,len); //复数
}
return 0;
}