Codeforces 1114E - Arithmetic Progression - [二分+随机数]

题目连接:http://codeforces.com/problemset/problem/1114/Eios

 

题意:c++

交互题,有一个 $n$ 个整数的打乱顺序后的等差数列 $a[1 \sim n]$,保证公差为正整数,你能够询问不超过 $60$ 次来找到该等差数列的首项和公差。spa

你能够作的询问有两种:code

  一、询问是否存在某个数字大于 $x$。blog

  二、询问序列中第 $i$ 个数是多少。ci

 

题解:get

首先能够用二分的方式找到这个等差数列的最大值,因为 $a[i] \in [0,1e9]$,因此最多 $30$ 次询问就能够找到这个最大值。博客

而后咱们能够用剩下的 $30$ 次询问随机查询一些位置,将这些数做差,求出全部差值的最大公因数,就是公差。it

另一个须要注意的点是https://codeforces.com/blog/entry/61587这篇博客中提到的,普通的rand()给出的随机数在 $[0,RAND\_MAX]$ 之间,可是只能保证 $RAND\_MAX$ 不小于 $32767$,所以在这个地方随机数的取值范围太小了,所以能够选用一些更好的随机数生成器 mt_rand 。io

 

 

AC代码:

#include<bits/stdc++.h>
using namespace std;

int n;
map<int,bool> mp;

int Find()
{
    int l=0, r=1e9;
    while(l<r)
    {
        int mid=(l+r)/2;
        cout<<"> "<<mid<<endl;
        int x; cin>>x;
        if(x) l=mid+1;
        else r=mid;
    }
    return l;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    cin>>n;
    int mx=Find();

    int d=0;
    mt19937 rnd(64708915);
    for(int i=1;i<=min(30,n);i++)
    {
        int idx;
        while(idx=rnd()%n+1)
        {
            if(mp.count(idx)) continue;
            mp[idx]=1;
            break;
        }
        cout<<"? "<<idx<<endl;
        int x; cin>>x;
        d=__gcd(d,mx-x);
    }
    cout<<"! "<<mx-(n-1)*d<<' '<<d<<endl;
}
相关文章
相关标签/搜索