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 }
posted @ 2016-09-03 19:37  lcf2000  阅读(293)  评论(0编辑  收藏  举报