bzoj1046(HAOI2007)上升序列
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1046
可贪心。关键是知道每个点最长能否>=x。所以先倒着做一个最长下降子序列就行了。
自己没有想清楚贪心的必要性和可行性,更没有想到贪心需要的这个处理。
自己只是分析求LIS的过程,发现它记录的是长度为k的最小值而不是字典序最小值,字典序反而会被更新得越来越大;
所以自己也想要不倒着做最长下降子序列,通过正常的进程来使得到的字典序最小;但是发现字典序仍旧可能不更新而导致不是最小。
这道题的思路明明很简单……还是要多锻炼思维。
注意代码里的那个>。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=1e4+5,INF=0x7fffffff; int n,m,a[N],dp[N],cnt,cd[N]; int main() { scanf("%d",&n); for(int i=n;i;i--)scanf("%d",&a[i]); a[dp[0]]=INF; for(int i=1;i<=n;i++) { if(a[dp[cnt]]>a[i]) { dp[++cnt]=i;cd[i]=cnt; continue; } int l=1,r=cnt,tp=1; while(l<=r) { int mid=((l+r)>>1); if(a[dp[mid]]>a[i])l=mid+1;//>a[i],不是>= (等于则可取代) else tp=mid,r=mid-1; } dp[tp]=i;cd[i]=tp; } scanf("%d",&m); int x,tp; for(int i=1;i<=m;i++) { scanf("%d",&x);tp=-INF; if(cnt<x) { printf("Impossible\n");continue; } else { for(int j=n;j;j--) if(cd[j]>=x&&a[j]>tp) { printf("%d ",a[j]);tp=a[j]; x--;if(!x)break; } printf("\n"); } } return 0; }