题面
分析
通过二分答案,我们显然可以求出数组中最大的数,即等差数列的末项
接着随机取一些数组中的数,对他们两两做差,把得到的差取gcd即为公差
例a={1,5,9,13},我们随机取了1 9 13,两两的差为8,4,12,取gcd为4
已知末项和公差即可求出首项
可以证明错误的概率< \(1.86185\times10?^{-9}\)
具体证明我也不懂,可以看cf官方题解,需要用到莫比乌斯反演
注意生成随机数时不能直接用rand(),因为rand()的返回值<32768,而n很可能>32768,需要用rand()*rand()再%n
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
int n;
int ask1(int x){
printf("? %d\n",x);
fflush(stdout);
int ans=0;
scanf("%d",&ans);
return ans;
}
int ask2(int x){
printf("> %d\n",x);
fflush(stdout);
int ans=0;
scanf("%d",&ans);
return ans;
}
int asks=0;
int bin_search(int l,int r){
int ans=0;
while(l<=r){
int mid=(l+r)>>1;
asks++;
if(ask2(mid)){
l=mid+1;
}else{
ans=mid;
r=mid-1;
}
}
return ans;
}
int a[62];
inline int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
inline int random(){
return (long long)rand()*rand()%n+1;
}
int main(){
srand(19260817);
scanf("%d",&n);
fflush(stdout);
int x=bin_search(0,1e9+1);
// printf("debug:%d\n",x);
for(int i=1;i<=60-asks;i++){
a[i]=ask1(random());
}
int ans=0;
for(int i=1;i<=60-asks;i++){
for(int j=i+1;j<=60-asks;j++){
ans=gcd(ans,abs(a[i]-a[j]));
}
}
printf("! %d %d\n",x-ans*(n-1),ans);
}
原文地址:https://www.cnblogs.com/birchtree/p/10360859.html
时间: 2024-10-09 09:19:36