最长上升子序列
Peter would like to find another sequence b1,b2,...,bnb1,b2,...,bn in such a manner that F(a1,a2,...,an)F(a1,a2,...,an) equals to F(b1,b2,...,bn)F(b1,b2,...,bn). Among all the possible sequences consisting of only positive integers, Peter wants the lexicographically smallest one.
The sequence a1,a2,...,ana1,a2,...,an is lexicographically smaller than sequence b1,b2,...,bnb1,b2,...,bn, if there is such number ii from 11 to nn, that ak=bkak=bk for 1≤k<i1≤k<i and ai<biai<bi.
InputThere are multiple test cases. The first line of input contains an integer TT, indicating the number of test cases. For each test case:
The first contains an integer nn (1≤n≤100000)(1≤n≤100000) -- the length of the sequence. The second line contains nn integers a1,a2,...,ana1,a2,...,an (1≤ai≤109)(1≤ai≤109).OutputFor each test case, output nn integers b1,b2,...,bnb1,b2,...,bn (1≤bi≤109)(1≤bi≤109) denoting the lexicographically smallest sequence.
Sample Input
3 1 10 5 5 4 3 2 1 3 1 3 5
Sample Output
1 1 1 1 1 1 1 2 3
解法1:
摘自大神的 lower——bound解释
函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置
举例如下:
一个数组number序列为:4,10,11,30,69,70,96,100.设要插入数字3,9,111.pos为要插入的位置的下标
则
pos = lower_bound( number, number + 8, 3) - number,pos = 0.即number数组的下标为0的位置。
pos = lower_bound( number, number + 8, 9) - number, pos = 1,即number数组的下标为1的位置(即10所在的位置)。
pos = lower_bound( number, number + 8, 111) - number, pos = 8,即number数组的下标为8的位置(但下标上限为7,所以返回最后一个元素的下一个元素)。
所以,要记住:函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置,且last的位置是越界的!!~
返回查找元素的第一个可安插位置,也就是“元素值>=查找值”的第一个元素的位置
#include <cstdio> #include <iostream> #include <algorithm> #include <limits.h> #define MAX 100005 using namespace std; int dp[MAX],a[MAX],b[MAX]; int main() { int T; scanf("%d",&T); while(T--) { int n; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) b[i]=INT_MAX; for(int i=1;i<=n;i++) { int pos=lower_bound(b+1,b+n+1,a[i])-b; dp[i]=pos; b[pos]=a[i]; } for(int i=1;i<=n-1;i++) printf("%d ",dp[i]); printf("%d\n",dp[n]); } return 0; }
解法二:
#include<cstdio> #include<algorithm> using namespace std; int number[100005],dp[100005],inc[100005]; int main() { int n,length,low,high,tail,mid; scanf("%d",&n); while (n--) { tail = dp[0] = 0; scanf("%d",&length); for (int i = 1; i <= length; i++) { scanf("%d",&number[i]); low = 0; high = tail - 1; while (high >= low) { mid = (low + high) / 2; if (dp[mid] >= number[i]) { high = mid - 1; } else { low = mid + 1; } } if (low >= tail) { tail++; } dp[low] = number[i]; inc[i] = low + 1; } printf("%d",inc[1]); for (int l = 2; l <= length; l++) { printf(" %d",inc[l]); } printf("\n"); } return 0; }

浙公网安备 33010602011771号