Quantcast
Channel: プログラミング
Viewing all articles
Browse latest Browse all 8151

ABC363挑戦記 - JunKobayashi’s diary

$
0
0

基本的な事項の学習が不十分すぎたため悲しみの2完😭😭😭😭😭😭😭😭😭

C++のstd::next_permutationがどのように振る舞うのかを正しく理解していなかったというあまりにもくだらなすぎる理由での失点となったため、今後は二度と同じ轍を踏まぬようにこの記事で確認できるようにする。

 

<A問題>

↓問題のページ↓

A - Piling Up

 

解(\(S\)と表す)は以下の通り。\begin{equation}
  S=
  \begin{cases}
    100 & \text{if $R  \equiv $0 $\pmod {100} $,} \\
    100 - (R \mod 100) & \text{otherwise} \\
  \end{cases}
\end{equation}

 

<B問題>

↓問題のページ↓

B - Japanese Cursed Doll

 

\(N\)も\(T\)も最大で\(100\)と小さいので、難しいことを一切考えず愚直に\(0\)日後時点から全探索するだけで間に合う。より具体的には、毎日\(N\)人全てに対し、\(L_i \gt T\)を満たすような\(i\)の個数を数える。これが\(P\)以上であればその時点での経過日数を出力して終了し、そうでなければ各\(L_i\)に対して\(1\)を加算すれば良い。

 

<C問題>

↓問題のページ↓

C - Avoid K Palindrome 2

 

\(N\)が最大で\(10\)と非常に小さいため、公式解説の通り、順列を全列挙してそれぞれに対して確認するだけで間に合う・・・のだが、冒頭の通り、std::next_permutationを正しく理解していなかったためstd::unordered_setを使い、無駄な処理を発生させてしまったせいでTLEを最後まで解消できずに終了。あまりにも不甲斐なすぎるためstd::next_permutationをこの記事でしっかりと確認する。

1)vectorやstringを対象にstd::next_permutationを使うことができる。

2)引数として与えた対象が辞書的順序で次にやって来る順列を持つのならばtrueを返し、対象を1つ先の順列に変える。持たなければfalseを返す。

3)要素数を\(n\)とし、全てが異なる要素ならば当然\(n!\)通りの順列全てを見ることができる。\(n\)要素の中に重複するものがある場合、全ての順列\(n!\)通りの中には2度以上現れるものが少なくとも1つは存在することになるが、同じ順列を2度以上見ることはない。

※順列を全探索する場合には、予め各要素を昇順ソートしておいて最初に現れる順列としておく必要がある。

 

<std::next_permutationの使用例>

#include 
#include 
#include 
using namespace std;

int main() {
  string s;
  cin >> s;

  // 事前に昇順ソートして最初の順列にする
  sort(s.begin(), s.end());

  cout << "-----" << endl;
  cout << "start" << endl;
  cout << "-----" << endl;

  while (1) {
    cout << s << endl;

    if (!next_permutation(s.begin(), s.end())) {
      break;
    }
  }
  cout << "-----" << endl;
  cout << " end " << endl;
  cout << "-----" << endl;
}

 

上記のコードを実行し、入力として"123"と"bcba"を与えた場合の実行結果を以下に記載する。重複要素がある場合も、確かに同じ順列を2度以上見ていないのが分かる。

1)重複要素がない場合

123
-----
start
-----
 0: 123
 1: 132
 2: 213
 3: 231
 4: 312
 5: 321
-----
 end
-----

 

2)重複要素がある場合(以下のように、\(4! = 24\)通り全てではなく、重複する順列を2度以上見ないため、\( \displaystyle{  \frac{4!}{2!}   = 12}\)通りのみを列挙してくれる。したがって、答えとしてあり得るような文字列を重複して数えないことを意図してstd::unordered_setに逐一insertするというようなことは一切必要ない。単にnext_permutationによってやって来た順列が条件を満たしているかどうかを判定し、適切であれば数え上げ用の変数に1を加算するというようにするだけで良い)

bcba
-----
start
-----
 0: abbc
 1: abcb
 2: acbb
 3: babc
 4: bacb
 5: bbac
 6: bbca
 7: bcab
 8: bcba
 9: cabb
10: cbab
11: cbba
-----
 end
-----


Viewing all articles
Browse latest Browse all 8151

Trending Articles