bzoj2875 [Noi2012]随机数生成器
Description
栋栋最近迷上了随机算法,而随机数生成 是随机算法的基础。栋栋准备使用线性同余法(Linear Congruential Method)来生成一个随机数列,这种方法需要设置四个非负整数参数m, a, c, X0,按照下面的公式生成出一系列随机数<Xn>:
Xn+1 = (aXn
+
c) mod m ,mod m 表示前面的数除以m的余数。从这个式子可以看出,这个序列的下一个数总是由上一个数生成的。
用这种方法生成的序列具有随机序列的性质,因此这种方法被广泛地使用,包括常用的C++和Pascal
的产生随机数的库函数使用的也是这种方法。
栋栋知道这样产生的序列具有良好的随机性,不过心急的他仍然想尽快知道Xn 是多少。由于栋栋需要的随机数是0,
1,…, g − 1 之间的,他需要将Xn除以g。取余得到他想要的数,即Xn mod
g,你只需要告诉栋栋他想要的数Xn mod g 是多少就可以了。
Input
包含6个用空格分割的m,a,c,X0,n和g,其中a,c,X0是非负整数,m,n,g是正整数。
Output
输出一个数,即Xn mod g
Sample Input
11 8 7 1 5 3
Sample Output
2
HINT
1<=n,m,a,c,X0<=10^18,1<=g<=10^8
正解:递推+矩阵快速幂。
矩阵快速幂水题。我用龟速乘居然T了,改成防爆乘轻松AC。。
初始矩阵:
x0 c
0 0
转移矩阵:
a 0
1 1
然后快速幂搞搞就行了。。
1 //It is made by wfj_2048~ 2 #include <algorithm> 3 #include <iostream> 4 #include <complex> 5 #include <cstring> 6 #include <cstdlib> 7 #include <cstdio> 8 #include <vector> 9 #include <cmath> 10 #include <queue> 11 #include <stack> 12 #include <map> 13 #include <set> 14 #define inf (1<<30) 15 #define il inline 16 #define RG register 17 #define ll long long 18 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) 19 20 using namespace std; 21 22 struct data{ ll a[3][3]; }ans,b; 23 24 ll m,a,c,x,n,g; 25 26 il ll mul(RG ll a,RG ll b){ 27 RG ll res=a*b-(ll)((long double)(a)*b/m+0.5)*m; 28 if (res<0) res+=m; return res; 29 } 30 31 il data matrix(RG data a,RG data b){ 32 RG data ans; memset(ans.a,0,sizeof(ans.a)); 33 for (RG ll i=1;i<=2;++i) 34 for (RG ll j=1;j<=2;++j) 35 for (RG ll k=1;k<=2;++k){ 36 ans.a[i][j]+=mul(a.a[i][k],b.a[k][j]); 37 if (ans.a[i][j]>=m) ans.a[i][j]-=m; 38 } 39 return ans; 40 } 41 42 il data qpow(RG data a,RG ll b){ 43 RG data ans=a; b--; 44 while (b){ 45 if (b&1) ans=matrix(ans,a); 46 a=matrix(a,a),b>>=1; 47 } 48 return ans; 49 } 50 51 il void work(){ 52 cin>>m>>a>>c>>x>>n>>g; 53 b.a[1][1]=a,b.a[2][1]=b.a[2][2]=1,b=qpow(b,n); 54 ans.a[1][1]=x,ans.a[1][2]=c,ans=matrix(ans,b); 55 printf("%lld\n",ans.a[1][1]%g); return; 56 } 57 58 int main(){ 59 File("rand"); 60 work(); 61 return 0; 62 }