正题
题目链接:https://jzoj.net/senior/#contest/show/3011/0
题目大意
给出n,m,a,b,c,x0n,m,a,b,c,x_0n,m,a,b,c,x0
xi=axi−12+bxi−1+cx_i=ax_{i-1}^2+bx_{i-1}+cxi=axi−12+bxi−1+c
求xn%mx_n\%mxn%m
解题思路
第一段n≤1e6n\leq 1e6n≤1e6直接O(n)O(n)O(n)暴力做
第二段m≤1e6m\leq 1e6m≤1e6找到一个循环节然后在套到n里
第三段:
xi=axi−12+bxi−1+cx_i=ax_{i-1}^2+bx_{i-1}+cxi=axi−12+bxi−1+c
学过二次函数的对于给出的性质有敏锐的直觉
xi=a(x+b2a)2+4ac−b24ax_i=a(x+\frac{b}{2a})^2+\frac{4ac-b^2}{4a}xi=a(x+2ab)2+4a4ac−b2
4ac=b2−2b⇒4ac−b2=2b4ac=b^2-2b\Rightarrow 4ac-b^2=2b4ac=b2−2b⇒4ac−b2=2b
xi=a(x+b2a)2−b2ax_i=a(x+\frac{b}{2a})^2-\frac{b}{2a}xi=a(x+2ab)2−2ab
然后定义k=b2ak=\frac{b}{2a}k=2ab
xi+k=a(x+k)2x_i+k=a(x+k)^2xi+k=a(x+k)2
同时乘上aaa
a(xi+k)=(a(x+k))2a(x_i+k)=(a(x+k))^2a(xi+k)=(a(x+k))2
定义yi=a(xi+k)y_i=a(x_i+k)yi=a(xi+k)
那么有yi=yi−12y_i=y_{i-1}^2yi=yi−12
即yn=y02ny_n=y_{0}^{2^n}yn=y02n
用费马小可以让指数摸上m−1m-1m−1计算出yny_nyn,然后倒推出xnx_nxn
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll M=1e6+10;
ll n,m,a,b,c,x,fa[M],cir[M],v[M];
void solve1(){for(ll i=1;i<=n;i++)x=(a*x%m*x%m+b*x%m+c)%m;printf("%lld",x);
}
void solve2(){x%=m;for(ll i=0;i<=m;i++)fa[i]=(a*i%m*i%m+b*i%m+c)%m;ll cnt=0;cir[0]=x;v[x]=1;while(!v[x=fa[x]])cir[++cnt]=x,v[x]=cnt;x=v[x];if(n<=cnt) printf("%lld",cir[n]);else{n-=x;printf("%lld",cir[x+n%(cnt-x+1)]);}
}
ll power(ll x,ll b,ll p){ll ans=1;while(b){if(b&1) ans=ans*x%p;x=x*x%p;b>>=1;}return ans;
}
void solve3(){ll z=b/2/a,y=a*(x+z)%m;y=power(y,power(2,n,m-1),m);printf("%lld",(y*power(a,m-2,m)%m-z+m)%m);
}
int main()
{scanf("%lld%lld%lld%lld%lld%lld",&x,&a,&b,&c,&n,&m);x=x%m;a%=m;b%=m;c%=m;if(n<=1e6)solve1();else if(m<=1e6)solve2();else solve3();
}