tags
交互
二分
中文题面
Arithmetic Progression
题面翻译
交互题。
有一个长度为 n n n 的序列 a a a,保证它从小到大排序后是个等差数列。你不知道这个序列长什么样,但你可以询问:
- ? i ?\ i ? i 表示询问 a i a_i ai 的值;
-
>
x
>\ x
> x 表示询问序列中是否存在严格大于
x
x
x 的数。
你可以问不超过 60 60 60 个询问。
现在,你需要求出这个等差数列的首项(也就是 a a a 中的最小值)和这个等差数列的公差(也就是等差数列中相邻两个数的差)。
2 ≤ n ≤ 1 0 6 , 0 ≤ a i ≤ 1 0 9 2\le n\le 10^6,0\le a_i\le 10^9 2≤n≤106,0≤ai≤109。
思路
最小元素很好找,我们只要利用询问2,二分查找即可,这个查找过程最多30次,剩余30次机会
a+(n-1)d = b
先问出一个元素,分别假设它等差数列的第2-n个元素,用问出的其他元素检测是否有冲突即可
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define N (int)2e5 + 5
#define pdd pair<double, double>
#define pii pair<int, int>
int a, b, c, d, x, y, n, m, t, k, q, l, r, p, z, h;
int num[N];
string s;
map<int, int> mp;
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
// 注意根据数据量调整N的大小
cin >> n;
l = 0, r = 1e9;
int ans = 0;
int cnt = 0;
while (l<=r) {
int mid = l+ r >> 1;
cout << "> " << mid << endl;
cnt++;
cin >> x;
if (x == 0) ans = mid, r = mid - 1;
else l = mid + 1;
}
int cc = 0;
// ans就是最大的
int aj = -1;
vector<int> dt;
for (int i = 1; i <= n && cnt < 60; i++, cnt++) {
cout << "? " << i << endl;
cin >> x;
if (aj==-1&&x!=ans) {
aj=x;
} else dt.push_back(x);
}
int mn = 1e18;
int xx = 0;
for (int i = 1; i < n; i++) {
// (n-i)d=an-aj;
if ((ans-aj)%(n-i)!=0) continue;
d = (ans-aj)/(n-i);
int x1 = ans - (n - 1) * d;
int f = 1;
if (x1 < 0) continue;
for (int &j : dt) {
// x1 + (k - 1) * d == dt;
if ((j-x1<0)||(j - x1) % d!=0) {
f = 0;
break;
}
}
if (!f) continue;
if (d < mn) mn=d,xx=x1;
}
cout << "! " << xx << ' ' << mn << endl;
return 0;
}