您的位置:首页 > 其它

BZOJ 1046 [HAOI2007]上升序列 DP

2013-03-12 23:37 399 查看
不知道什么印象,好像以前见过,记得要把数列倒过来的~

nlogn的最长上升子序列。

但是方案不好搞~

PS:看好是谁的字典序最小。。。

换个问题,

假设知道以a[i]为开头的最长下降子序列的长度,是不是就好搞了?

方法是从左往右,直接贪心的选这个i(以a[i]为开头的最长下降子序列的长度要大于你需要的长度)一定是能使字典序最小~

前面说了,倒过来做就行了, 因为我们只会求以a[i]结尾的最长上升子序列的长度。。。

View Code

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <algorithm>

#define N 111111
#define INF 0x3f3f3f3f
#define BUG system("pause")

using namespace std;

int n,a
,b
,dp
;
int len,stk
,p,cas,m;

inline void read()
{
scanf("%d",&n);
for(int i=n;i>=1;i--) scanf("%d",&a[i]);
}

inline void step1()
{
len=1;
for(int i=0;i<=n;i++) b[i]=-INF;
b[0]=INF; b[1]=a[1]; dp[1]=1;
for(int i=2;i<=n;i++)
{
int l=0,r=len+1,mid,res;
while(l<=r)
{
mid=(l+r)>>1;
if(b[mid]>a[i]) res=mid,l=mid+1;
else r=mid-1;
}
len=max(res+1,len);
b[res+1]=max(b[res+1],a[i]);
dp[i]=res+1;
}
reverse(a+1,a+1+n);
reverse(dp+1,dp+1+n);
}

inline void step2()
{
if(len<m) {puts("Impossible");return;}
p=0;
int last=-INF;
for(int i=1;i<=n&&m!=0;i++)
if(dp[i]>=m&&a[i]>last) stk[++p]=i,m--,last=a[i];
for(int i=1;i<p;i++) printf("%d ",a[stk[i]]);
printf("%d\n",a[stk[p]]);
}

inline void go()
{
step1();
scanf("%d",&cas);
while(cas--)
{
scanf("%d",&m);
step2();
}
}

int main()
{
read(),go();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: