Codeforces 1114E(数学+随机算法)

题面

传送门

分析

通过二分答案,我们显然可以求出数组中最大的数,即等差数列的末项

接着随机取一些数组中的数,对他们两两做差,把得到的差取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);
}


猜你喜欢

转载自www.cnblogs.com/birchtree/p/10360859.html