【洛谷2215】【HNOI 2007】上昇シーケンス
タイトルの説明
与えられたS={a 1,a 2,a 3,...,an}に対して、P={ax 1,ax 2,ax 3,...,axm}があれば、満足する(x 1
にゅうしゅつりょくけいしき
入力形式:
1行目はN個で、シーケンスが全部でN個の要素があることを示し、2行目はN個で、a 1,a 2,...,an 3行目はM個で、問い合わせ回数を表す.次に、M行の1行あたりの数Lと続き、長さLの立ち上がりシーケンスを尋ねることを示す.
出力フォーマット:
各問合せについて、対応するシーケンスが存在する場合は出力、そうでない場合はImpossibleを印刷する.
入出力サンプル
サンプル#1を入力:
出力サンプル#1:
説明
データ範囲N<=10000 M<=1000
問題解
データ範囲が10000なので、n^2のLISを求めるのは無理で、ツリー配列で最適化できますが、この問題はm回の問い合わせがあるので、以前のツリー配列のLISを求めるのとは違って、今回f[i]はiを先頭とするLISの長さ(辞書順最小(符号)であるため)を表し、樹状配列が求められないことを発見した.今回求めたのはそれより大きいmaxであるため、小さなテクニックを用いて樹状配列を逆さにし、iという数の位置がn-i+1になり、これで大きな数が前になり、小さい数が後になるので、接頭辞maxを求めることができる(とても巧みです).
与えられたS={a 1,a 2,a 3,...,an}に対して、P={ax 1,ax 2,ax 3,...,axm}があれば、満足する(x 1
にゅうしゅつりょくけいしき
入力形式:
1行目はN個で、シーケンスが全部でN個の要素があることを示し、2行目はN個で、a 1,a 2,...,an 3行目はM個で、問い合わせ回数を表す.次に、M行の1行あたりの数Lと続き、長さLの立ち上がりシーケンスを尋ねることを示す.
出力フォーマット:
各問合せについて、対応するシーケンスが存在する場合は出力、そうでない場合はImpossibleを印刷する.
入出力サンプル
サンプル#1を入力:
6
3 4 1 2 3 6
3
6
4
5
出力サンプル#1:
Impossible
1 2 3 6
Impossible
説明
データ範囲N<=10000 M<=1000
問題解
データ範囲が10000なので、n^2のLISを求めるのは無理で、ツリー配列で最適化できますが、この問題はm回の問い合わせがあるので、以前のツリー配列のLISを求めるのとは違って、今回f[i]はiを先頭とするLISの長さ(辞書順最小(符号)であるため)を表し、樹状配列が求められないことを発見した.今回求めたのはそれより大きいmaxであるため、小さなテクニックを用いて樹状配列を逆さにし、iという数の位置がn-i+1になり、これで大きな数が前になり、小さい数が後になるので、接頭辞maxを求めることができる(とても巧みです).
#include
#include
#include
#include
using namespace std;
const int maxn=10010;
int n,m,k,a[maxn],b[maxn],c[maxn],ans[maxn],num;
int t[maxn],f[maxn];
int lowbit(int x){
return x&(-x);
}
void add(int x,int y){
x=n-x+1;
for(int i=x;i<=n;i+=lowbit(i))
t[i]=max(t[i],y);
}
int find(int x){
x=n-x+1;// , , max
int ans=0;
for(int i=x;i>=1;i-=lowbit(i))
ans=max(t[i],ans);
return ans;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
c[i]=b[i]=a[i];
}
sort(b+1,b+n+1);
num=unique(b+1,b+n+1)-b-1;
for(int i=1;i<=n;i++){
c[i]=lower_bound(b+1,b+num+1,c[i])-b;
}
/* for(int i=1;i<=n;i++)
cout<=1;i--){
f[i]=find(c[i]+1)+1;
add(c[i],f[i]);
len=max(len,f[i]);
}
scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%d",&k);
if(k>len){
printf("Impossible
");
}
else{
last=0;
for(int i=1;i<=n;i++)
if(f[i]>=k&&a[i]>last){
if(k==0) break;
else{
printf("%d ",a[i]);
k--;
last=a[i];
}
}
printf("
");
}
}
return 0;
}