Description
Input
一行,六个整数,分别表示 x0, a, b, c, n, m。
Output
一行,一个整数,表示 xn mod m 的值。
Sample Input
1 1 1 1 5 1000000000
Sample Output
133904603
Data Constraint
分析:
前35%数据,直接暴力枚举即可,复杂度O(n)O(n)。
另外35%数据,我们发现对mm取模余数不同的数只有个,一旦出现了一个相同的数就出现循环节,即可通过。注意循环节不一定从x0x0开始,前面的一些数可能没有循环,要先减去。复杂度O(m)O(m)。
最后30%数据,有
xi=axi−12+bxi−1+cxi=axi−12+bxi−1+c
根据二次函数相关知识,化为顶点式,
xi=a(xi−1+b2a)2+4ac−b24axi=a(xi−1+b2a)2+4ac−b24a
由题意得,4ac−b2=−2b4ac−b2=−2b,得
xi=a(xi−1+b2a)2−2b4axi=a(xi−1+b2a)2−2b4a
移项得,
xi+b2a=a(xi−1+b2a)2xi+b2a=a(xi−1+b2a)2
假设数列TT,有,上式为,
Ti=aTi−12Ti=aTi−12
两边同时乘aa,得
那么,
aTn=(aT0)2naTn=(aT0)2n
得,
xn=a2n−1∗(x0+b2a)2n−b2axn=a2n−1∗(x0+b2a)2n−b2a
因为mm是质数,可以对指数模。
复杂度O(logn)O(logn)
其实考场上觉得mm这个条件很重要,对想用原根了,其实也是可以做的,可以把乘法变为指数加法,设a=gca=gc,那么每次相当于把指数乘2再加c,矩阵加速递推就可以了,这样复杂度是O(sqrt(n)+logn)O(sqrt(n)+logn)。然后一开始没取模直接gg了。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#define LL long long
const int maxn=1e7+7;
using namespace std;
LL x,a,b,c,n,p,k;
LL A[maxn],B[maxn];
LL ksm(LL x,LL y,LL p)
{
if (y==1) return x;
LL c=ksm(x,y/2,p);
c=(c*c)%p;
if (y%2) c=(c*x)%p;
return c;
}
int main()
{
scanf("%lld%lld%lld%lld%lld%lld",&x,&a,&b,&c,&n,&p);
LL t=b/(2*a);
x%=p; a%=p; b%=p; c%=p;
if (n<=1e7)
{
for (int i=1;i<=n;i++) x=(a*x%p*x%p+b*x%p+c)%p;
printf("%lld",x);
}
else
{
if (p<=1e6)
{
A[0]=x;
B[x]=0;
for (int i=1;i<=n;i++)
{
x=(a*x%p*x%p+b*x%p+c)%p;
if (B[x]!=0)
{
k=i-B[x];
break;
}
A[i]=x;
B[x]=i;
}
n=(n-B[x])%k+B[x];
printf("%lld",A[n]);
}
else
{
LL d=ksm(2,n,p-1);
LL s=((d-1)+(p-1))%(p-1);
LL ans=(ksm(a,s,p)*ksm((x+t)%p,d,p)%p+p-t)%p;
printf("%lld",ans);
}
}
}