問題
AtCoder Beginner Contest 269 E問題
アプローチ
上下それぞれ10回までなら質問が出来るので、二分探索で左の境界から真ん中までのルークの数を聞き、その数が探索区間と同じ長さならそこには候補地はない為、左の境界を真ん中に移す、そうでなければ右の境界を真ん中にうつし、返ってきた数が0のときこそがまさしく求めたい行/列であると考える。
該当コード
C++
1#include <bits/stdc++.h> 2#include <math.h> 3#include <algorithm> 4using namespace std; 5#define ll long long 6 7void solve() { 8 ll N; cin >> N; 9 10 ll left = 1; 11 ll right = N; 12 ll y; 13 while (true) { 14 ll mid = (left + right) / 2; 15 cout << "?" << " " << 1 << " " << N << " " << left << " " << mid << endl; 16 ll T; cin >> T; 17 if (T == 0) { 18 y = mid; 19 break; 20 } 21 else if (T == mid - left + 1) { 22 left = mid + 1; 23 } 24 else { 25 right = mid; 26 } 27 } 28 29 ll top = 1; 30 ll bottom = N; 31 ll x; 32 while (true) { 33 ll mid2 = (top + bottom) / 2; 34 cout << "?" << " " << top << " " << mid2 << " " << 1 << " " << N << endl; 35 ll T; cin >> T; 36 if (T == 0) { 37 x = mid2; 38 break; 39 } 40 else if (T == mid2 - top + 1) { 41 top = mid2 + 1; 42 } 43 else { 44 bottom = mid2; 45 } 46 } 47 48 cout << "!" << " " << x << " " << y << endl; 49} 50 51int main() { 52 solve(); 53}
質問
上のコードを通そうとすると、大型のケースでは「正解」でかつ「不正解」は出力されないものの、10個ほどのケースで時間切れを起こします。個人的には左右の境界の設定の仕方かwhileループの抜け出し方に問題があるとは疑っているのですが、具体的にどのような例においてループから抜けられないのかがわからずにいます。どこかお力添え頂ける箇所がございましたら、ご教授のほどよろしくお願い申し上げます。
1000 の要素で二分探索を行うとき、一回目のクエリで候補は最悪 500 になります。
同様に二回目のクエリで 250、三回目で 125、四回目で 63、五回目で 32、六回目で 16、七回目で 8、八回目で 4、九回目で 2、十回のクエリが終わって候補が 1 残っています。
つまり、T が 0 になるまで続けるのであれば、最悪 11 回のクエリを投げなくてはいけません。

回答2件
あなたの回答
tips
プレビュー