T446080 百战名 讲解

· · 题解

题目

递推题。
题目简述:给你 a,b,c,p,n,使 x_1,x_2ax^2+bx+c=0 的两根,求 (x_1^n+x_2^n)\bmod p

众所周知,一元二次方程的公式是 \displaystyle x=\frac{-b\pm\sqrt{b^2-4ac}}{2a},但是最后的小数取模就很难弄,我们应该换个思路。

我们往递推的角度想,设 f_i=(x_1^i+x_2^i)\bmod p,则:

\begin{aligned}f_i&=(x_1^i+x_2^i)\bmod p\\&=(x_1^i+x_2^i+x_1^{i-1}x_2+x_1x_2^{i-1}-x_1^{i-1}x_2-x_1x_2^{i-1})\bmod p\\&=((x_1+x_2)(x_1^{i-1}+x_2^{i-1})-x_1x_2(x_1^{i-2}+x_2^{i-2}))\bmod p\\&=((x_1+x_2)f(i-1)-x_1x_2f(i-2))\bmod p\end{aligned}

这样我们就推出了状态转移方程,那么(\Delta=b^2-4ac):

\begin{aligned}x_1+x_2&=\frac{-b+\sqrt\Delta}{2a}+\frac{-b-\sqrt\Delta}{2a}\\&=\frac{-b+\sqrt\Delta-b-\sqrt\Delta}{2a}\\&=\frac{-2b}{2a}\\&=\frac{-b}{a}\end{aligned}

我们用 exgcd(费马小定理也可以)求逆,exgcd 详见 P1495 【模板】中国剩余定理(CRT)/ 曹冲养猪 讲解。

\begin{aligned}x_1x_2&=(\frac{-b+\sqrt\Delta}{2a})(\frac{-b-\sqrt\Delta}{2a})\\&=\frac{(-b+\sqrt\Delta)(-b-\sqrt\Delta)}{4a^2}\\&=\frac{b^2-b\sqrt\Delta+b\sqrt\Delta-\Delta}{4a^2}\\&=\frac{b^2-\Delta}{4a^2}\\&=\frac{b^2-(b^2-4ac)}{4a^2}\\&=\frac{4ac}{4a^2}\\&=\frac{c}{a}\end{aligned}

同上用 exgcd 求 \displaystyle\frac{c}{a}

这样我们成功得到了矩阵 res

\begin{bmatrix}\frac{-b}{a}&-\frac{c}{a}\\1&0\end{bmatrix}

然后我们得到 res^{n-2},再来一个矩阵 ans

\begin{bmatrix}f_2\\f_1\end{bmatrix} $$\begin{aligned}f_2&=x_1^2+x_2^2\\&=x_1^2+x_2^2+2x_1x_2-2x_1x_2\\&=(x_1+x_2)^2-2x_1x_2\\&=(\frac{-b}{a})^2-\frac{2c}{a}\end{aligned}$$ 这样 $res^{n-2}\times ans$ 的 $a_{1,1}$ 就是答案。 代码: ```cpp #include<bits/stdc++.h> #define int long long #define inl inline #define INF LLONG_MAX #define rep(i,x,y) for(int i=x;i<=y;++i) #define rer(i,x,y,cmp) for(int i=x;i<=y&&cmp;++i) #define per(i,x,y) for(int i=x;i>=y;--i) #define FAST ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #define endl '\n' using namespace std; int a,b,c,p,n,x,y,sum,ts,numm; struct matrix{ int a[5][5]; inl matrix init(){ matrix res; memset(res.a,0,sizeof(res.a)); return res; } inl matrix init2(){ matrix res=init(); res.a[1][1]=res.a[2][2]=1; return res; } inl friend matrix operator*(matrix a,matrix b){ matrix res=res.init(); rep(i,1,2) rep(j,1,2) rep(k,1,2) (res.a[i][j]+=a.a[i][k]*b.a[k][j])%=p; return res; } inl friend matrix operator^(matrix a,int b){ matrix num=a,ans=ans.init2(); while(b){ if(b&1) ans=ans*num; num=num*num; b>>=1; } return ans; } }ans,num; inl void exgcd(int a,int b,int p){ if(p==0){ x=a; y=0; return; } exgcd(a,p,b%p); int tx=x; x=y; y=tx-b/p*y; } signed main(){ FAST; cin>>a>>b>>c>>p>>n; exgcd(-b,a,p); sum=((x%p)+p)%p; exgcd(c,a,p); ts=((x%p)+p)%p; numm=(sum*sum%p-(ts<<1)%p+p)%p; ans=num=ans.init(); num.a[1][1]=numm; num.a[2][1]=sum; ans.a[1][1]=sum; ans.a[1][2]=((-ts)%p+p)%p; ans.a[2][1]=1; if(n==1){ cout<<sum; return 0; } if(n==2){ cout<<numm; return 0; } ans=ans^(n-2); ans=ans*num; cout<<ans.a[1][1]; return 0; } ```