BZOJ - 5427:最长上升子序列 (二分&思维)
现在给你一个长度为n的整数序列,其中有一些数已经模糊不清了,现在请你任意确定这些整数的值,
使得最长上升子序列最长。(为何最长呢?因为hxy向来对自己的rp很有信心)
第一行一个正整数n
接下来n行第i行格式如下
K x:表示第i个数可以辨认且这个数为x
N:表示第i个数一个已经辨认不清了
(n<=100000,|x|<=10^9)
Output
一个正整数代表最长上升子序列最长是多少
Sample Input
4
K 1
N
K 2
K 3
Sample Output
3
题意:有一个序列,有些位置的数由你来决定,求LIS。
思路:首先我们知道求LIS可以用二分来优化,那么我们维护一个上升的序列,用dp[i]表示长度为i的LIS的最后一位最小是多少,每次新加入一个数的时候,用x去替换upper_bound的位置即可。
然而这个题有未知数,未知数可以由自己决定,所以每个未知数都要使用比较优,对于每个dp[i],可以用dp[i]+1去更新dp[i+1],即右移一位,我们用add来表示。
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=100010; int dp[maxn],add; int main() { dp[0]=-(1e9+10); int N,x,R=0; char c[4]; scanf("%d",&N); rep(i,1,N){ scanf("%s",c+1); if(c[1]=='K'){ scanf("%d",&x); int l=0,r=R,pos,mid; while(l<=r){ mid=(l+r)>>1; if(dp[mid]+add<x) { l=mid+1; pos=mid;} else r=mid-1; } if(pos==R) dp[++R]=x-add; else dp[pos+1]=min(dp[pos+1],x-add); } else add++; } printf("%d\n",R+add); return 0; }
It is your time to fight!