CF1114E Arithmetic Progression

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 2n106,0ai109

思路

最小元素很好找,我们只要利用询问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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值