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; }
转载请注明出处:https://dilthey.cnblogs.com/