質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

例外

例外(exception)とは、プログラムの処理実行中に発生する、通常の処理の続行を妨げる特殊な事象のことを呼びます。この「例外」が発生した場合に、現在の処理を中断し、変わりに別の処理を実行させる事を「例外処理」と呼びます。

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

884閲覧

AtCoder / 二分探索で例外が処理しきれない

kay_ventris4

総合スコア269

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

例外

例外(exception)とは、プログラムの処理実行中に発生する、通常の処理の続行を妨げる特殊な事象のことを呼びます。この「例外」が発生した場合に、現在の処理を中断し、変わりに別の処理を実行させる事を「例外処理」と呼びます。

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2021/06/14 12:25

編集2021/06/15 00:43

#問題
イメージ説明
AtCoder Beginner Contest 205 D問題 より

#今回参考にしている入力例
イメージ説明

#方針
checkとliの1つのリストは、各Kの入力に対してそれに対応する今回の問題の答えが「check[i]より大きい時(iはそのような条件を満たす最小の値)、その答えの値からli[i]を引いたものがKである」と言う風に考え設定しました。例えば、「入力例1」で言うとK2にあたる5について言えば、それに対応する答えの9が「check[4] = 7より大きい時、その答えの値からli[4] = 4を引いたもの(=5)がKである」といった要領です。この方針ではAC×21, WA×2でほとんどのテストケースには正解しているのですが、ごく一部のケースで間違いであるようです。昨日行われたばかりのコンテストであるため、テストケース自体は未だ公開されておりません。

#ソースコード

Python

1from itertools import accumulate 2from bisect import bisect_left 3 4N, Q = map(int, input().split()) 5A = list(map(int, input().split())) 6 7check = [0] + [a for a in A] 8li = [0] + list(accumulate([1 for _ in range(len(check) - 1)])) 9#[0, 3, 5, 6, 7] 10#[0, 1, 2, 3, 4] 11 12def find_ind(k): 13 left = 1 14 right = 10 ** 19 15 while right - left > 1: 16 mid = (left + right) // 2 17 if mid - li[bisect_left(check, mid) - 1] <= k: 18 left = mid 19 else: 20 right = mid 21 return left 22for _ in range(Q): 23 K = int(input()) 24 print(find_ind(K))

#考えたこと・質問
何か見えない例外が発生し、本当の答えが実はleftではなくrightなのではないか?と言うことを考え、leftが条件式left - li[bisect_left(check, left) - 1] == kを満たさない場合はrightを代わりに出力するようにしても、やはり該当のテストケース2つでWAをくらったため、leftにもrightにも正解がないようなケースが発生していることがわかりました。どのような見落としが考えられるのでしょうか。自分で思いつくケースは色々と模索したものの一向に答えにたどり着く兆しが見えません。お力添え頂ける箇所がございましたら、ご教授のほど何卒よろしくお願い申し上げます。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

例えば、この問題文のプログラムで以下の入力を実行すると明らかに間違った答えが出ます。

2 1 2 999999999999999999 1000000000000000000

期待する答えは 1000000000000000002になるはずですが、実行結果は 999999999999999999 になります。
これは意地悪な境界値ケースで発生します。テストケースにkillerとついていますが、おそらく「二分木探索での実装者を殺しに来る」意味合いなのかなと思います。問題文のミスリードを利用した引っ掛け問題です。

A,Nともに取りうる値は10^18までですが、数列Aの最大数が10^6あるため、答えとなりうる値が最大で10^10+10^6あることになります。このプログラムでは答えとして取りうる値の最大値をright側に入れて開始していますが、最大値が実際に取りうる最大値に足りていないので答えとして10^18以上の数値が来た場合にこれ以上の数が探索できずにleftにひたすらmidが加算されていきます。最終的にright未満の数値である10^18-1までしかleftが増加しません。

なので、対策としてはrightの初期値をもう少し増やしてあげれば良い、ということになります。最低10^18 + 10^6 + 1 あれば大丈夫だと思いますが、それより大きい値でも2倍程度なら処理速度に大差ありません。10^18*2くらいで開始すれば問題なくACが取れると思います。

なお、このコードをpypyではなくpythonで実行するとLTEだらけになります。処理速度をもっと向上させるアルゴリズムを考えるのも勉強になるかと思います。

投稿2021/06/14 21:42

編集2021/06/14 21:49
hope_mucci

総合スコア4447

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kay_ventris4

2021/06/15 00:45

ご教授頂いた通りrightの上限を大きめに取ったところ、全てACしました。 下限の検討はしていたのですが、答えの上限を検討するところを怠っておりました。 ご丁寧にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問