Bellovin Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 707 Accepted Submission(s): 328 Problem Description Peter has a sequence a1,a2,...,an and he define a function on the sequence -- F(a1,a2,...,an)=(f1,f2,...,fn), where fi is the length of the longest increasing subsequence ending with ai. Peter would like to find another sequence b1,b2,...,bn in such a manner that F(a1,a2,...,an) equals to F(b1,b2,...,bn). Among all the possible sequences consisting of only positive integers, Peter wants the lexicographically smallest one. The sequence a1,a2,...,an is lexicographically smaller than sequence b1,b2,...,bn, if there is such number i from 1 to n, that ak=bk for 1≤k<i and ai<bi. Input There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case: The first contains an integer n (1≤n≤100000) -- the length of the sequence. The second line contains n integers a1,a2,...,an (1≤ai≤109). Output For each test case, output n integers b1,b2,...,bn (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 Source BestCoder Round #84 Recommend wange2014 | We have carefully selected several similar problems for you: 5751 5750 5749 5747 5746
树状数组:
/* 对于普通的LIS: for(i):1~n LIS[i]=1; if j<i and a[j]<a[i] LIS[i]=LIS[j]+1 因此可知LIS转移需要两个条件 1.(j<i) 序号必须在i之前 2.(a[i]>a[j]) 值必须比a[i]小 利用树状数组的顺序操作:{查找的都是已经出现的,序号在前(满足条件1)} 对于每一个值,查找它在数组中的排名,再去寻找小于它的排名的最大的LIS(满足条件2) 这里利用到了排名,因为这样可以最大限度地压缩C数组的空间 */ #include <bits/stdc++.h> using namespace std; const int Max=1e5+10; int A[Max],V[Max],L[Max],C[Max],len; int lowbit(int x) {return x&(-x);} int Sum(int x) //求值小于等于x的LIS的最大值 { int ret=0; while(x>0) { if(C[x]>ret) ret=C[x]; x-=lowbit(x); } return ret; } void Add(int x,int d) //值大于等于x的LIS都改为LIS(x) { while(x<=len) { if(d>C[x]) C[x]=d; x+=lowbit(x); } } int main() { int T; for(scanf("%d",&T);T;T--) { int n; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&A[i]); V[i]=A[i]; } sort(V+1,V+1+n); len=unique(V+1,V+1+n)-(V+1); memset(C,0,sizeof(C)); int ans=1,tmp,xu; for(int i=1;i<=n;i++) { xu=lower_bound(V+1,V+1+len,A[i])-(V); tmp=Sum(xu-1)+1; L[i]=tmp; Add(xu,tmp); } for(int i=1;i<=n;i++) { if(i!=1) printf(" "); printf("%d",L[i]); } puts(""); } return 0; }
dp+二分
/* 以dp[x]代表长度为x的LIS,且dp[x]==LIS长度为x的末尾值 每次都往前取dp[x]中最小的一个,当然在保证x尽可能地大的情况下 因为dp[x]是递增的,所以可以二分,l=1,r=当前最长的LIS 求得当前以小于当前a[i]的最长LIS */ #include <bits/stdc++.h> using namespace std; const int Max=1e5+10; int A[Max]; int dp[Max]; int LIS[Max]; void Get_lis(int n) { int i,j,l,r,mid,ans; dp[1]=A[1]; int len=1; for(i=2;i<=n;i++) { if(dp[len]<A[i]) j=++len; else { l=1;r=len; ans=0; while(l<=r) { mid=(l+r)>>1; if(A[i]>dp[mid]&&A[i]<=dp[mid+1]) { ans=mid;break; } else if(A[i]>dp[mid]) l=mid+1; else r=mid-1; } j=ans+1; } dp[j]=A[i]; LIS[i]=j; } } int main() { int T; for(scanf("%d",&T);T;T--) { int n; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&A[i]); dp[i]=0; } LIS[1]=1; Get_lis(n); for(int i=1;i<=n;i++) { if(i!=1) printf(" "); printf("%d",LIS[i]); } puts(""); } return 0; }
其实还有一种单调队列求最长上升子序列的方法,可是不能用来解这道题
/* 无解。。。 单调队列只能求出总体的LIS长度 */ #include <bits/stdc++.h> using namespace std; const int Max=1e5+10; int que[Max],LIS[Max]; int main() { int T; for(scanf("%d",&T);T;T--) { int n,x,top=1; scanf("%d",&n); scanf("%d",&x); que[top]=x; LIS[1]=1; for(int i=2;i<=n;i++) { scanf("%d",&x); if(x>que[top]) { que[++top]=x; } else { int l=1,r=top,mid,ans; ans=0; while(l<=r) { mid=l+(r-l)/2; if(que[mid]<x) l=mid+1,ans=mid; else r=mid-1; } que[ans]=x; } } cout<<top<<endl; } return 0; }
时间: 2024-10-22 16:59:42