E - Guess the Root 拉格朗日差值法+交互

题目传送门

  题意:告诉你存在一个未知项系数最高为10的$f(x)$,你最多可以有50次询问,每次询问给出一个$x'$,系统会返回你$f(x')$的值,你需要猜一个$x''$,使得$f(x'')=0$,所有运算都是取模1e6+3下进行的。

  思路:拉格朗日插值法的模板题。yyb聚聚的公式

  $p(x)=$\sum\limits_{n}^{i=0}$(-1)n-i*p(i)*x*(x-1)*(x-2)*(x-3)*……*(x-n)/((n-i)! * i! * (x-i))$

       所以先暴力询问0-10的所有答案,然后判断11-p的答案是否为0即可。

#include<bits/stdc++.h>
#define CLR(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const ll p=1e6+3;
ll a[11],f[20],jcinv[20],inv[p+2];
ll qpow(ll a,ll b){
    ll res=1;
    a%=p;
    while(b){
        if(b&1)res=res*a%p;
        b>>=1;
        a=a*a%p;
    }
    return res;
}
void init(){
    f[0]=1;
    for(int i=1;i<=13;i++)f[i]=f[i-1]*i%p;
    jcinv[13]=qpow(f[13],p-2);
    for(int i=13;i>0;i--){
        jcinv[i-1]=jcinv[i]*i%p;
    }
    inv[1]=1;
    for(int i=2;i<=p;i++)
    {
        inv[i]=inv[p%i]*(p-p/i)%p;
    }
}
int main(){
    init();
    for(int i=0;i<=10;i++)
    {
        printf("? %d\n",i);
        fflush(stdout);
        scanf("%lld",&a[i]);
        if(a[i]==0){
            printf("! %d\n",i);
            fflush(stdout);
            return 0;
        }
    }
    for(int k=11;k<p;k++)
    {
        ll up=1;
        for(int i=0;i<=10;i++)up=up*(k-i)%p;
        ll res=0;
        for(int i=0;i<=10;i++)
        {
            ll tep=0;
            tep=a[i]*up%p*jcinv[10-i]%p*jcinv[i]%p*inv[k-i]%p;
            res=(res+tep*(i%2==0?1:-1)+p)%p;
        }
        if(res==0){
            printf("! %d\n",k);
            fflush(stdout);
            return 0;
        }
    }
    printf("! -1\n");
    fflush(stdout);
}

 

posted @ 2019-04-23 20:13  光芒万丈小太阳  阅读(318)  评论(0编辑  收藏  举报