BZOJ1046 上升序列

题解:

神TM的字典序最小。。。。。。这题的字典序最小是位置的字典序最小。。。仔细读读题目

所以。我们求出以每个点为起点的最长递增子序列。。然后输出的话。贪心就行

如何求每个点为起点的最长递增子序列

回忆一下LIS的o(nlog(n))算法

我们逆向求最长递减子序列即可.

代码:

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define mp make_pair
#define se second
#define fs first
#define ll long long
#define CLR(x) memset(x,0,sizeof x)
#define MC(x,y) memcpy(x,y,sizeof(x))
#define SZ(x) ((int)(x).size())
#define FOR(it,c) for(__typeof((c).begin()) it=(c).begin();it!=(c).end();it++)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define INF 2097152
typedef pair<int,int> P;
const double eps=1e-9;
const int maxn=10010;
const int mod=10007;

ll read()
{
    ll x=0,f=1;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x*f;
}
//-----------------------------------------------------------------------------

int a[maxn],b[maxn],c[maxn],f[maxn];

int bs(int m,int l,int r)//大于m的最小数
{
    int L,R,Mid,Goal;
    L=1,R=r+1;
    while(L<=R)
    {
        Mid=(L+R)>>1;
        if(c[Mid]>m)
        {
            Goal=Mid;
            L=Mid+1;
        }
        else R=Mid-1;
    }
    return Goal;
}

int main()
{
    int n,m,p;
    n=read();
    for(int i=1;i<=n;i++)
    {
        a[i]=read();
        b[n+1-i]=a[i];
    }
    int tmp=1;
    c[tmp]=b[1];
    f[n]=1;
    for(int i=2;i<=n;i++)
    {
        if(b[i]<c[tmp])
        {
             c[++tmp]=b[i];
             f[n+1-i]=tmp;
        }
        else
        {
            int pos=bs(b[i],1,tmp);
            f[n+1-i]=pos+1;
            if(c[pos+1]<b[i]) c[pos+1]=b[i];
        }
    }
    m=read();
    a[0]=-INF;
    int pos;
    for(int i=1;i<=m;i++)
    {
        p=read();
        if(p>tmp) printf("Impossible\n");
        else
        {
            pos=0;
            for(int i=1;i<=n;i++)
            {
                if(!p) break;
                if(f[i]>=p&&a[i]>a[pos])
                {
                    if(p>1) printf("%d ",a[i]);
                    else    printf("%d\n",a[i]);
                    p--;
                    pos=i;
                }
            }
        }
    }
    return 0;
}
时间: 2024-10-25 00:38:06

BZOJ1046 上升序列的相关文章

[bzoj1046][HAOI2007]上升序列

题意:对于一个给定的S={a1,a2,a3,-,an},若有P={ax1,ax2,ax3,-,axm},满足(x1 < x2 < - < xm)且( ax1 < ax2 < - < axm).那么就称P为S的一个上升序列. 有m个询问,每次询问一个长度L,如果没有长度为L的上升序列,输出Impossible,要不然求一个字典序最小的上升序列. (这题的字典序最小居然指的是下标) n<=10000,m<=1000 题解:倒着dp,用线段树求出每个点和它后面最长

【bzoj1046】[HAOI2007]上升序列

首先求出以每个数为开头上升序列长度,即倒着做最长下降子序列 然后,把字典序尽量小的放前面 即若要求的序列长度为x,如果以第一个数(字典序最小的数)开头的最长上升子序列大等于x,则将它放在答案第一个,第二个数开头小于x,则舍弃,第三个大于x-1,放答案第二个,以此类推 #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio>

[BZOJ1046] [HAOI2007] 上升序列 (dp)

Description 对于一个给定的S={a1,a2,a3,…,an},若有P={ax1,ax2,ax3,…,axm},满足(x1 < x2 < … < xm)且( ax1 < ax2 < … < axm).那么就称P为S的一个上升序列.如果有多个P满足条件,那么我们想求字典序最小的那个.任务给出S序列,给出若干询问.对于第i个询问,求出长度为Li的上升序列,如有多个,求出字典序最小的那个(即首先x1最小,如果不唯一,再看x2最小……),如果不存在长度为Li的上升序列

【动态规划】【最长上升子序列】【贪心】bzoj1046 [HAOI2007]上升序列

nlogn求出最长上升子序列长度. 对每次询问,贪心地回答.设输入为x.当前数a[i]可能成为答案序列中的第k个,则若 f[i]>=x-k && a[i]>ans[k-1] 即可. f[i]表示以a[i]开头的最长上升子序列长度. 但这个东西难以统计.so 我们将原序列反序,求f[i] 表示以 a[i]为结尾的最长下降子序列长度即可.最后再将f.a reverse一下. 1 #include<cstdio> 2 #include<algorithm> 3

【BZOJ-1046】上升序列 DP + 贪心

1046: [HAOI2007]上升序列 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3723  Solved: 1271[Submit][Status][Discuss] Description 对于一个给定的S={a1,a2,a3,…,an},若有P={ax1,ax2,ax3,…,axm},满足(x1 < x2 < … < xm)且( ax1 < ax2 < … < axm).那么就称P为S的一个上升序列.如果有多

[BZOJ1046][HAOI2007]上升序列 DP+贪心

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1046 我们先求出对于每一个数字作为开头的LCS的长度f[i],最长的f[i]为mxlen. 对于每一个询问,我们选取答案,从第1个开始选.假设当前已经选到了第x个答案,我们只需要一直往后面找到第一个f[k]且f[k]+x>mxlen,它就是第x+1个答案. 这样时间复杂度就是$O(nm)$的,感觉玄学卡过…… 1 #include<cstdio> 2 #include<cs

如何理解“字符串是一组由16位组成的不可变的有序序列”

疑惑点: 1.16位 2.不可变 3.有序序列 解惑: 1.16位指的是:字符串每个字符所占用的空间为16bits 比特(2 bytes);这是因为JS采用的是unicode编码,每个字符需要2个字符. 2.不可变指的是: 字符串对象一旦创建出来,便不能被更改.这可能有些难理解,但事实确实如此.你可能会认为s+='1' 只是在 s 后面增加一个元素 1 而已,但事实是: 先将 s 拷贝一份,记为 temp 在 temp 末尾加上'1' 将 s 变量指向 temp,并删去原来的s 这一特性,可以从

BZOJ 3992 【SDOI2015】 序列统计

题目链接:序列统计 我来复习板子了--这道题也是我写的第一发求原根啊? 求原根方法: 从小到大依次枚举原根.设当前枚举的原根为\(x\),模数为\(p\),\(p-1\)的质因数分别为\(p_1,p_2,\dots,p_m\),则只需检验\(x^{\frac{p}{p_i}}\equiv1 \pmod{p}\)是否成立即可.如果成立则\(x\)不是原根. 然后这道题朴素\(dp\)就不讲了.设\(m\)的原根为\(g\),那么把每个数表示成\(g^k\)的形式就可以乘法变加法了,就成为了\(NT

k序列和

二分答案是参数搜索的一个改善.是这样,对于一个问题,如果它的答案具有单调性质(即如果i不可行,那么大于i的解都不可行,而小于i的解有可能可行),进而用二分的方法枚举答案,再判断答案是否可行,直到求到符合条件为止.例如:问题的答案范围是1到w之间的一个整数,求最小解,那么我们设s=1,t=w,之后mid=(s+t)整除2.然后判断当解是mid的时候这个问题能不能解决,如果能解决则和最优解比较,并且范围缩小到s到mid-1之间(因为即使这个范围没有解,那么mid是最小解):如果不能解决问题,则最小解