これはインタラクティブな問題です。
ホーマーはアレイが大好きで、あなたとゲームをしたいと思っています。
ホーマーはあなたから順列a1、a2、…、整数1からnまでを隠しました。極小値であるインデックスk(1≤k≤n)を見つけるように求められます。
アレイのための1、2、...、nは、インデックスi(1≤i≤n)があると言われている極小場合I <分間{ I-1 、I + 1 }、ここで0 = a n + 1 = +∞。配列に1からnまでのすべての整数が1回だけ含まれている場合、配列は1からnまでの整数の順列であると言われます。
最初は、この順列に関する他の情報なしで、nの値のみが与えられます。
インタラクティブな各ステップで、任意のi(1≤i≤n)を選択し、それを使用してクエリを実行できます。応答として、aiの値が与えられます。
最大100回のクエリの後、極小値であるインデックスkを見つけるように求められます。
インタラクション
あなたは、整数n(1≤n≤10読み取ることによって対話を開始する5を別々の行に)。
インデックスi(1≤i≤n)でクエリを実行するには、「?別の行に「i」。次に、別の行でaiの値を読み取ります。「?」の数 クエリは100以内に制限されています。
極小値であるインデックスk(1≤k≤n)を見つけたら、「!k」を別の行に入力して、プログラムを終了します。
クエリ形式が無効な場合、または100を超える「?」を作成した場合 クエリを実行すると、間違った回答の評決が表示されます。
クエリを出力した後、行末を出力して出力をフラッシュすることを忘れないでください。そうしないと、アイドル状態の制限を超えてしまいます。これを行うには、次を使用します。
- C ++のfflush(stdout)またはcout.flush()。
- JavaのSystem.out.flush();
- Pascalのflush(output);
- Pythonのstdout.flush();
- 他の言語のドキュメントを参照してください。
ハックフォーマット
ハッキングの最初の行は、単一の整数n(1≤n≤10含むべきである5)。
2行目は、N個の別個の整数含むべきである1、2、...、N(1≤a I ≤n)。
例
入力
5
3
2
1
4
5
出力
?1
?2
?3
?4
?5
!3
注意
この例では、最初の行に整数5が含まれており、配列の長さがn = 5であることを示しています。
この例では、5つの「?」を作成します クエリを実行すると、配列はa = [3,2,1,4,5]であり、k = 3は極小値であると結論付けられます。
一般的なアイデア
1からnまでのすべての順列を格納する長さnの配列があります。100以下のクエリで極小値を見つける必要があります。最初は、配列のサイズのみがわかります。配列の各位置の値は、
分析
3点で最小値を見つけ、間隔を[l、r]、mid =(l + r)>> 1に設定します。a[mid + 1]> a [mid]の場合、最小値は左側でなければなりません。ミッド+1側(mid + 1を除く)の場合、最小値はミッドの右側(ミッドを除く)である必要があります。配列a []は1〜nの完全な配列を格納するため、a [mid]が存在する必要があります。 ≠[中間+ 1]、時間複雑性O(ログ(N))
分析によって、総クエリの最大数は2⌈logある2質問の要件を満たしてn⌉≤34<100、
ACコード
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int a[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n;
cin>>n;
int l=1,r=n;
while(l<r)
{
int mid=(l+r)>>1;
cout<<"? "<<mid<<endl;
cin>>a[mid];
cout<<"? "<<mid+1<<endl;
cin>>a[mid+1];
if(a[mid+1]>a[mid]) r=mid;
else l=mid+1;
}
cout<<"! "<<l<<endl;
return 0;
}
問題解決コード
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100010;
int n;
int a[MAXN];
int query(int x)
{
if (1 <= x && x <= n)
{
printf("? %d\n", x);
fflush(stdout);
scanf("%d", &a[x]);
}
}
int main()
{
scanf("%d", &n);
a[0] = a[n + 1] = n + 1;
int L = 1, R = n;
while (L < R)
{
int m = (L + R) / 2;
query(m);
query(m + 1);
if (a[m] < a[m + 1])
R = m;
else
L = m + 1;
}
printf("! %d\n", L);
fflush(stdout);
return 0;
}
注意
1. Codeforcesインタラクティブ問題の紹介インタラクティブ問題:参加者向けガイド
2.バッファの更新に注意してください。cout<< endlを使用すると、バッファが自動的に更新されます。printfを使用する場合は、fflush(stdout);を追加する必要があります。