1. 程式人生 > >【bzoj】1046: [HAOI2007]上升序列

【bzoj】1046: [HAOI2007]上升序列

升序 open one end pan cst isp stdin 一道

  作為一個蒟蒻,頭一回在bzoj這個神奇的oj上寫題(A+B這麽難的題就不說了)

  廢話不多說,先讓dalao們看看題吧:

  題目描述

   對於一個給定的S={a1,a2,a3,…,an},若有P={ax1,ax2,ax3,…,axm},滿足(x1 < x2 < … < xm)且( ax1 < ax
2 < … < axm)。那麽就稱P為S的一個上升序列。如果有多個P滿足條件,那麽我們想求字典序最小的那個。任務給
出S序列,給出若幹詢問。對於第i個詢問,求出長度為Li的上升序列,如有多個,求出字典序最小的那個(即首先
x1最小,如果不唯一,再看x2最小……),如果不存在長度為Li的上升序列,則打印Impossible.

  輸入

   第一行一個N,表示序列一共有N個元素第二行N個數,為a1,a2,…,an 第三行一個M,表示詢問次數。下面接M
行每行一個數L,表示要詢問長度為L的上升序列。N<=10000,M<=1000

  輸出

  對於每個詢問,如果對應的序列存在,則輸出,否則打印Impossible.

  樣例

    輸入:

       6
       3 4 1 2 3 6
       3
       6
       4
       5

     輸出:

      Impossible

      1 2 3 6
      Impossible

  就是這一道題,還叫我調了好長時間

  看到這道題都知道是用DP+貪心就行,先將數組倒過來遍歷求出第i個點以後的最長不下降序列的長度

  然後記錄一下最長不下降序列的長度,如果詢問時的值x>max最長不下降序列的長度,那麽就輸出“Impossible”

  之後正著遍歷一遍找到第一個f[i]==x時,用數組開始記錄下答案就好。

  註意:1.因為每次ans數組中加入一個數,x--,所以要保證x!=0因為最長不下降子序列長度不可能為0(這個坑了我一回....)

  2.這裏面的按照字典序輸出,我是看bzoj中討論說:這字典序並不是按照數的大小而是按照這個數在數組中的位置(這很字典序)

  3.輸出序列時最後不要再輸出空格

  代碼如下:

  

技術分享
#include<iostream>
#include<cstring>
#include
<algorithm> #include<cstdio> #include<cmath> using namespace std; int a[11000]; int f[11000]; bool b[11000]; int ans[11000]; int main() { //freopen("add.in","r",stdin); //freopen("add.out","w",stdout); int n; cin>>n; memset(b,false,sizeof(b)); memset(f,0,sizeof(f)); int k=0; for(int i=1;i<=n;i++) { cin>>a[i]; } for(int i=n;i>=1;i--) { for(int j=i+1;j<=n;j++) { if(a[i]<a[j]) f[i]=max(f[i],f[j]); } f[i]++; k=max(f[i],k); b[f[i]]=true; } int m; cin>>m; /*for(int i=1;i<=n;i++) cout<<f[i]<<‘ ‘; cout<<endl;*/ for(int i=1;i<=m;i++) { int x; cin>>x; /*if(b[x]!=true)*/ if(x>k) cout<<"Impossible"<<endl; else { int q=-100000; int l=0; for(int j=1;j<=n&&x!=0;j++) { if(f[j]>=x&&a[j]>q) { l++; ans[l]=a[j]; q=a[j]; x--; } } for(int j=1;j<l;j++) cout<<ans[j]<< ; cout<<ans[l]<<endl; } } return 0; }
(~ ̄▽ ̄)~

【bzoj】1046: [HAOI2007]上升序列