#费马小定理#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;
}
posted @ 2020-02-09 11:31  lemondinosaur  阅读(178)  评论(0编辑  收藏  举报