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

题目链接:http://codeforces.com/problemset/problem/1114/E

 

题意:

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

你可以做的询问有两种:

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

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

 

题解:

首先可以用二分的方式找到这个等差数列的最大值,由于 $a[i] \in [0,1e9]$,所以最多 $30$ 次询问就可以找到这个最大值。

然后我们可以用剩下的 $30$ 次询问随机查询一些位置,将这些数作差,求出所有差值的最大公因数,就是公差。

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

 

 

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;
}

 

posted @ 2019-03-08 16:50  Dilthey  阅读(326)  评论(0编辑  收藏  举报