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;
}

 

posted on 2018-06-06 19:55  Narh  阅读(133)  评论(0编辑  收藏  举报

导航