ARC091 E : LISDL(700)

作成日:2018.03.14
最終更新日:2018.03.14

問題概要

問題本文

 11からNNまでの整数からなる順列で、最長増加部分列(LIS)の長さがAA、最長減少部分列(LDS)の長さがBBであるものが存在するか判定せよ。 また存在する場合は、そのうちの一つを構成せよ。
制約
1N,A,B3×1051N,A,B3×105

考え方

 まずは数列が与えられた時にLIS及びLDSの長さを求めることを考える。 先頭からii個見た時にその数を含むLIS,LDSの長さをそれぞれaiai,bibiとすると、A=max(Ai)A=max(Ai),B=max(Bi)B=max(Bi)となる。 この時a1=b1=1であり、j<iを満たすあるjにおいてai=aj+1,bi=bjまたはai=aj,bi=bj+1である。 よってai+jiの増加量は高々1であるから、A+B2+(N1)=N+1である。 また1aiA,1biBであり、i>jかつai=ajかつbi=bjとすると数列の要素はいずれも異なることからLISまたはLDSのいずれかを大きくすることができるので矛盾する。 このことからNABが分かる。
 以上よりA+B1NABである必要がある。 N=ABを達成するために(ai,bi)の組をすべて作ることを考える。 規則正しく並べた(1,1),(1,2),...,(1,B),(2,1),(2,2),...,(A,B)ai,biの条件に反しない。 またこれをaiが等しいものをまとめてみると、前のまとまりにある要素よりも後のまとまりにある要素の方が大きい必要があることが分かる。 さらに、まとまりの中では要素の値が単調減少していることも分かる。 よってB,B1,...,2,1,2B,2B1,...,ABA+1,ABAと並べれば、N=ABを達成できる。 ここから不要な数を抜き出して詰めれば、他の場合も構成することができる。

ソースコード

マクロ等はこちら

  1. int N,A,B;
  2.  
  3. int main(){
  4. cin >> N >> A >> B;
  5. if(A+B-1>N || (LL)A*B<(LL)N){
  6. cout << -1 << endl;
  7. } else {
  8. int x = N - A;
  9. int m = 0;
  10. while(m<N){
  11. int y = 0;
  12. if(x>=B-1){
  13. y = B;
  14. } else {
  15. y = x+1;
  16. }
  17. repm(i,m+y,m) cout << i << ' ';
  18. m += y;
  19. x -= y-1;
  20. }
  21. cout << endl;
  22. }
  23. return 0;
  24. }

解法まとめ

 A+B1NABの時に条件を満たす順列が存在し、そうでない時は存在しない。(5,6行)
 構成は以下のように行えば良い。 1からNまで順に並べた数列を、各グループがB個以下となるようにA個のグループを先頭から順に整数をとっていくことで作る。 但しグループのうちの1つは必ずB個の要素を含むようにする。 グループ内の整数の最大値が小さいものから順に、グループ内では降順になるように並べる。(8-21行)

ARC091の他の問題 C D F

自己紹介

プログラミングとか合成音声とか
詳しくはこちら
twitter

プライバシーポリシー

個人情報利用についてはこちら

最終更新日:2023.03.05

お問い合わせ

このページに関するお問い合わせはこちら

競技プログラミングMENU

問題を解くまでの道のり

その他

全体MENU

寄付モドキ

0冂から10000冂まで
詳しくはこちら