最长上升序列 裸题 可以用树状数组 或者二分查找写
这个题目的话 要求的是以x为起点,求最长长度是多少,不同于以前的求y为终点的最长长度。
所以,我们把数组倒过来处理,即求 从后往前,最长“下降序列”。
树状数组版:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<vector>
#include<queue>
using namespace std;
int lowbit(int x)
{
return x&(-x);
}
int c[11009];
void update(int x,int len)//c[x]保存的是到x这个位置,最长的上升序列的长度,len表示插入的上升序列的长度
{
while(x<=11009)
{
c[x]=max(len,c[x]);
x+=lowbit(x);
}
return ;
}
int query(int x)
{
int an=0;
while(x>=1)
{
an=max(an,c[x]);
x-=lowbit(x);
}
return an;
}
struct node
{
int id,num,numinst;//numinst 表示插入的“实际值” 经过排序处理以后,相当于求 从后往前的最长上升子序列 这样我们就能用树状数组进行处理了
} nod[10009];
bool cmp1(node a,node b)
{
return a.id<b.id;
}
bool cmp2(node a,node b)
{
return a.num>b.num;
}
int dp[10009];
int main()
{
int n,m,i,j,x;
scanf("%d",&n);
for(i=0; i<n; i++)
{
scanf("%d",&nod[i].num);
nod[i].id=i;
}
sort(nod,nod+n,cmp2);//按照他们的大小从大到小排序
nod[0].numinst=1;
for(i=1; i<n; i++)//处理实际应该插入的位置
{
nod[i].numinst=nod[i-1].numinst;
if(nod[i].num!=nod[i-1].num)nod[i].numinst++;
}
sort(nod,nod+n,cmp1);
for(i=n-1; i>=0; i--)//这里循环的顺序要从n-1~0 从后往前扫描
{
dp[i]=query(nod[i].numinst-1)+1;
update(nod[i].numinst,dp[i]);
}
scanf("%d",&m);
int ans[10009],num;
for(i=0; i<m; i++)
{
scanf("%d",&x);
j=0;
num=0;
int tem=-1111111;
while(x>0&&j<n)
{
if(dp[j]>=x&&nod[j].num>tem)
{
ans[num++]=nod[j].num;
tem=nod[j].num;
x--;
}
j++;
}
if(x>0)printf("Impossible\n");
else
{
for(j=0; j<num; j++)
{
if(j==0)printf("%d",ans[j]);
else printf(" %d",ans[j]);
}
printf("\n");
}
}
return 0;
}
下面的是 二分查找版的:来自ink姐姐。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
const int INF=1<<29;
int a[10005], c[10005], dp[10005];
int maxlen, n;
int get_pos(int va)
{
int mid, l=0, r=maxlen, ret=0;
while(l<=r){
mid=(l+r)>>1;
if(va<c[mid]){
l=mid+1;
ret=mid;
}else {
r=mid-1;
}
}
return ret;
}
void deal(int len)
{
int i, j, pre=-INF;
bool st=0;
for(i=1;i<=n&&len;i++){
if(dp[i]>=len&&a[i]>pre){
if(st) printf(" ");
st=1;
printf("%d",a[i]);
pre=a[i];
len--;
}
}
puts("");
}
int main()
{
int i, j, t, q;
while(~scanf("%d",&n)){
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
maxlen=0;
memset(c,0,sizeof(c));
c[0]=INF;
for(i=n;i>=1;i--){
dp[i]=get_pos(a[i])+1;
c[dp[i]]=max(c[dp[i]],a[i]);
maxlen=max(maxlen,dp[i]);
}
scanf("%d",&q);
for(i=1;i<=q;i++){
scanf("%d",&t);
if(maxlen<t) printf("Impossible\n");
else deal(t);
}
}
return 0;
}