#费马小定理#JZOJ 4015 数列
题目
给出\(x_n=(ax_{n-1}^2+bx_{n-1}+c)\bmod m\)
给出\(x_0.a,b,c,n,m\),求\(x_n\)
\(\text{Subtask 1:}n\leq 10^6,m\leq 10^9\)
\(\text{Subtask 2:}n\leq 10^9,m\leq 10^6\)
\(\text{Subtask 3:}n\leq 10^9,m\leq 10^9,2a|b,4ac+1=(b-1)^2,m是质数\)
分析
前两个子任务都很简单,第一个纯模拟,第二个循环节,第三个就有点难搞了,考虑用性质推式子
\(x_n=a(x_{n-1}+\frac{b}{2a})^2+\frac{4ac-b^2}{4a}\)
\(x_n=a(x_{n-1}+k)^2+\frac{(b-1)^2-b^2-1}{4a}=a(x_{n-1}+k)+{\frac{-2b}{4a}}=a(x_{n-1}+k)^2-k(k=\frac{b}{2a})\)
那么\(x_n+k=a(x_{n-1}+k)^2\)
设\(D_n=x_n+k\),通过推导可以得出\(D_n=a^{2^n-1}D_{0}^{2^n}\)
既然\(m\)是质数,就可以用费马小定理求解了
代码
#include <cstdio>
#define rr register
using namespace std;
int x0,a,b,c,n,mod;
inline signed mo(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline signed nxig(int x){return mo(1ll*mo(1ll*a*x%mod,b)*x%mod,c);}
inline void baoli(){
for (rr int i=1;i<=n;++i) x0=nxig(x0);
printf("%d",x0);
}
inline void floyd1(){
rr int p[1000011],ans[1000011],rep,len,pos;
for (rr int i=0;i<mod;++i) p[i]=-1; p[x0]=0,ans[0]=x0;
for (rr int i=1;i<=mod;++i){
if (i>n) break;
x0=nxig(x0),ans[i]=x0;
if (p[x0]==-1) p[x0]=i;
else {rep=p[x0]; len=i-p[x0]; break;}
}
if (n<rep) pos=n;
else pos=rep+(n-rep)%len;
printf("%d",ans[pos]);
}
inline signed ksm(int x,int y,int mod){
rr int ans=1;
for (;y;y>>=1,x=1ll*x*x%mod)
if (y&1) ans=1ll*ans*x%mod;
return ans;
}
inline void floyd2(){
rr int k=b/(a*2);
x0+=k,x0=1ll*ksm(1ll*a*x0%mod,mo(ksm(2,n,mod-1),mod-1),mod)*x0%mod,x0=mo(x0,mod-k);
printf("%d",x0);
}
signed main(){
scanf("%d%d%d%d%d%d",&x0,&a,&b,&c,&n,&mod),
x0%=mod,a%=mod,b%=mod,c%=mod;
if (n<=1000000) baoli();
else{
if (mod<=1000000) floyd1();
else floyd2();
}
return 0;
}