题意:
给定$x,y,n,a_{0},m,g$.
定义$a_{i}=x*a_{i-1}+y mod m$
求$a_{n} mod g$
$n,m,x,y,a<=10^{18},g<=10^{8}$
题解:
当n较小,可以直接算出$a_{n}$
可以得到$a_{n}$的通项公式 $a_{n}=x^{n}*a_{0}+y*frac{x^{n-1}-1}{x-1}$
当m是素数时,可以通过求解逆元得到结果.
对于没有特殊性质的数据该怎么做?
我们可以把递推式构造成矩阵
$egin{Bmatrix} a_{i} \ y end{Bmatrix} = egin{Bmatrix} x & 1 \ 0 & 1 end{Bmatrix} * egin{Bmatrix} a_{i-1} \ y end{Bmatrix} $
那就可以再$logn$内求出$a_{n}$
但是注意 $m$是LL范围的,所以中间结果可能会溢出.
对于这种情况 可以使用"快速乘" 用快速幂的思路把乘法转化成加法.这样就可以实现LL乘法了.
#include<cstdio> #include<cstring> #include<iostream> using namespace std; #define ll long long ll n,m,g,x,y,a; void Add(ll &x,ll y){x+=y;if(x>=m)x-=m;} ll mul(ll a,ll b){ ll res=0; while(b){ if(b&1)Add(res,a); Add(a,a); b>>=1; } return res; } struct Mat{ int a,b; ll c[2][2]; Mat(){c[0][0]=c[0][1]=c[1][0]=c[1][1]=0;} Mat operator*(const Mat &tmp)const{ Mat t; for(int i=0;i<a;i++){ for(int j=0;j<tmp.b;j++) for(int k=0;k<b;k++) Add(t.c[i][j],mul(c[i][k],tmp.c[k][j])); } t.a=a,t.b=tmp.b; return t; } void init(int x,int y){ a=x,b=y; } }I; ll calc(){ ll b=n; Mat t;t.init(2,2); t.c[0][0]=x,t.c[0][1]=t.c[1][1]=1; I.init(2,1); I.c[0][0]=a; I.c[1][0]=y; while(b){ if(b&1)I=t*I; t=t*t; b>>=1; } return I.c[0][0]; } int main(){ // freopen("random.in","r",stdin); cin>>m>>x>>y>>a>>n>>g; x%=m,y%=m,a%=m; cout<<calc()%g<<endl; return 0; }
$By LIN452$
$2017.06.09$