洛谷-P15427 Nobody Tells 题解

Solution

我们不能直接查询数列前几项,只能查询 \(L\le i<M\) 的位置。这意味着很可能需要利用数列本身的数学结构和性质。

我们需要一个可以让我们从任意靠后的几项推出 \(p,q\) 的性质。

这里直接上结论

\f_i\^2-f_{i-1}f_{i+1}\\equiv(-q)\^i \\

不难归纳证明。(专门对着这个式子出的题吧,没学过二阶齐次线性递推做不出来很正常)

最自然的想法是问 \(f_{M-3},f_{M-2},f_{M-1}\)。

此时根据结论,有

\f_{M-2}\^2-f_{M-3}f_{M-1}\\equiv(-q)\^{M-2} \\

由费马小定理,\((-q)^{M-2}\equiv(-q)^{-1}\),因此

\q\\equiv-\\left(f_{M-2}\^2-f_{M-3}f_{M-1}\\right)\^{-1} \\

我们就得到了 \(q\)。再来考虑如何得到 \(p\)。

由递推式得

\\\begin{aligned} f_{M-1}\&\\equiv qf_{M-3}+pf_{M-2} \\\\ pf_{M-2}\&\\equiv f_{M-1}-qf_{M-3} \\end{aligned} \\

此时如果 \(f_{M-2}\not\equiv 0\) 我们就做完了。接下来只需要考虑 \(f_{M-2} \equiv 0\) 的情况。

此时仅仅知道 \(f_{M-3},f_{M-2},f_{M-1}\) 肯定得不出 \(p\),尝试查询 \(f_{M-4}\)。

由结论得

\f_{M-3}\^2-f_{M-4}f_{M-2} \\equiv(-q)\^{M-3} \\

由费马小定理和 \(f_{M-2}\equiv 0\) 得

\f_{M-3}\^2\\equiv(-q)\^{-2} \\

因此 \(q\equiv\pm \frac{1}{f_{M-3}}\)。

显然 \(f_{M-3}\not\equiv 0\)(不然整个数列就全 \(0\) 了)。可以放心将解出的两个 \(q\) 代入 \(f_{M-2}\equiv pf_{M-3}+qf_{M-4}\) 解出两个 \(p\),分别提交即可。

最终交互策略:

步骤 操作
第一次 查询 \(f_{M-2}\)
第二次 查询 \(f_{M-3}\)
第三次,若 \(f_{M-2}\not\equiv0\) 查询 \(f_{M-1}\),求出唯一解
第三次,若 \(f_{M-2}\equiv0\) 查询 \(f_{M-4}\),求出两组解

Code

cpp 复制代码
#include <iostream>
#define int long long
using namespace std;
int m,l;
int query(int x){
    int res;
    cout<<"? "<<x<<endl;
    cin>>res;
    return res;
}
void guess(int p1,int q1,int p2,int q2){
    p1=(p1+m)%m,p2=(p2+m)%m;
    q1=(q1+m)%m,q2=(q2+m)%m;
    cout<<"! "<<p1<<' '<<q1<<' '<<p2<<' '<<q2<<endl;
}
int ksm(int x,int y){
    int res=1;
    while(y){
        if(y&1) (res*=x)%=m;
        (x*=x)%=m,y>>=1;
    }
    return res;
}
void solve(){
    cin>>m>>l;
    // f_{m-4}:a
    // f_{m-3}:b
    // f_{m-2}:c
    // f_{m-1}:d
    int c=query(m-2),b=query(m-3);
    if(c){
        int d=query(m-1);
        int q=-ksm((c*c%m-b*d%m)%m,m-2);
        int p=(d-q*b)%m*ksm(c,m-2)%m;
        guess(p,q,p,q);
    }else{
        int a=query(m-4);
        int q=ksm(b,m-2);
        int p=-q*a%m*ksm(b,m-2)%m;
        guess(p,q,-p,-q);
    }
}
signed main(){
    int T;
    cin>>T;
    while(T--) solve();
    return 0;
}