codevs 1281 Xn数列
题目描述 Description
给你6个数,m, a, c, x0, n, g
Xn+1 = ( aXn + c ) mod m,求Xn
m, a, c, x0, n, g<=10^18
输入描述 Input Description
一行六个数 m, a, c, x0, n, g
输出描述 Output Description
输出一个数 Xn mod g
样例输入 Sample Input
11 8 7 1 5 3
样例输出 Sample Output
2
很久没有写博客了……先写道水题压压惊
由于不想写矩乘(不要问我为什么),所以我就开始了推式子(其实就是想当做数学题来做)。
首先,由于$x_i=ax_{i-1}+c$,那么$x_n={a^nx_0+\sum_{i=0}^{n-1}a^ic}$
那么,写个快速幂,前面一部分就出来了。再设$f_x=\sum_{i=0}^{x}a^i$,$y=\lfloor x/2 \rfloor$,那么有:
$$ f_x= \begin{cases} (a^{y+1}+1)f_{y} &(x \bmod 2=1) \\ f_{x-1}+a^x&(x \bmod 2=0) \end{cases} $$
最后,由于模数是$10^{18}$级别的,还要写个快速乘法。
下面贴代码(好像一不小心多写了若干个$\log$):
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) 7 8 using namespace std; 9 typedef long long llg; 10 11 llg m,a,c,x0,g,n,ans; 12 13 void gi(llg &h){if(h>=m) h%=m;} 14 llg ch(llg a,llg b){ 15 llg s=0; 16 if(a<b) swap(a,b); 17 while(b){ 18 if(b&1) s+=a,gi(s); 19 a<<=1,gi(a); b>>=1; 20 } 21 return s; 22 } 23 24 llg mi(llg a,llg b){ 25 llg s=1; 26 while(b){ 27 if(b&1) s=ch(s,a); 28 a=ch(a,a); b>>=1; 29 } 30 return s; 31 } 32 33 llg solve(llg x){ 34 if(!x) return 1; 35 llg s,u=(x-1)>>1; 36 s=ch(solve(u),mi(a,u+1)+1); 37 if(!(x&1)) s+=mi(a,x),gi(s); 38 return s; 39 } 40 41 int main(){ 42 scanf("%lld %lld %lld %lld %lld %lld",&m,&a,&c,&x0,&n,&g); 43 ans=ch(mi(a,n),x0); 44 ans+=ch(solve(n-1),c); gi(ans); 45 printf("%lld",ans%g); 46 return 0; 47 }