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;
}
相關文章
相關標籤/搜索