【AtCoder】ABC 466 C - Count Close Pairs

実行時間制限: 2 sec / メモリ制限: 1024 MiB / Difficulty: 658 / NoviSteps: 2Q / 配点: 300 点
問題概要
数直線上に、点 , , , が 左から右に並んでいる。
最初、あなたには整数 のみが与えられる。
その後、あなたはジャッジに以下の質問を 回まで行うことができる。
? i j: を満たす整数 を選び、点 と点 の距離が 以下であるか質問する。
距離が 以下である場合は Yes、そうでない場合は No として、質問の答えがジャッジから標準入力に返される。
距離が 以下の 点組の個数 を以下の形式で出力せよ。
! X
制約
考察
ABCでは見慣れないインタラクティブ問題。
数直線上での点 の座標を とする。
点 に対して、自身よりも右側にあって、距離が 以下のもので最大の番号の点を とする:
このとき、点 と組にできる点の個数は、 の 個であるから、答えは
となる。
ここで重要なのが、 は単調増加するということである。
なぜなら、組 の距離が 以下であるなら、組 の距離も 以下であり、
が成り立つからである。
したがって、 に対して、尺取り法の要領で を単調増加に求めることができる。
? i j という質問の答えについて、
Yes: であることがわかるので、 を右に動かすことができる。No: であることがわかるので、今の の探索を終了して を右に動かすことができる。
という動きをすれば、質問回数は最大でも 回で済む。
実装例
1.#include <bits/stdc++.h>2.using namespace std;3. 4.#define rep(i, start, end) for (auto i = (start); (i) < (end); (i)++)5. 6.template <typename T>7.inline bool chmax(T& a, T b) { return ((a < b) ? (a = b, true) : (false)); }8. 9.// ======================================== //10. 11.bool query(int i, int j) {12. cout << "? " << i << " " << j << endl;13. cout << flush;14. 15. string res;16. cin >> res;17. 18. return res == "Yes";19.}20. 21.int main()22.{23. int N;24. cin >> N;25. 26. int ans = 0;27. int right = 1;28. rep(left, 1, N + 1) {29. chmax(right, left);30. 31. while (right + 1 <= N) {32. if (query(left, right + 1)) {33. right++;34. }35. else {36. break;37. }38. }39. 40. ans += right - left;41. }42. 43. cout << "! " << ans << endl;44. cout << flush;45. 46. return 0;47.}実装時間: 10分
コメント
かなり久々のインタラクティブ問題でぎょっとしたが、尺取り法そのままで解くことができ一安心。





