NOI2012 随机数生成器

题目描述

栋栋最近迷上了随机算法,而随机数是生成随机算法的基础。栋栋准备使用线性同余法(Linear Congruential Method)来生成一个随机数列,这种方法需要设置四个非负整数参数 \(m,a,c,X_0\),按照下面的公式生成出一系列随机数 \(\{X_n\}\):

\[X_{n+1}=(aX_n +c)\bmod m
\]

其中\(mod\ m\) 表示前面的数除以 \(m\) 的余数。从这个式子可以看出,这个序列的下一个数总是由上一个数生成的。

栋栋知道这样产生的序列具有良好的随机性,不过心急的他仍然想尽快知道 \(X_n\) 是多少。由于栋栋需要的随机数是 \(0,1,\dots,g-1\) 之间的,他需要将 \(X_n\)​ 除以 \(g\) 取余得到他想要的数,即 \(X_n \bmod g\),你只需要告诉栋栋他想要的数 \(X_n \bmod g\) 是多少就可以了。

输入格式

一行 \(6\) 个用空格分割的整数 \(m,a,c,X_0,n\) 和 \(g\),其中 \(a,c,X_0\) 是非负整数,\(m,n,g\) 是正整数。

输出格式

输出一个数,即 \(X_n \bmod g\)。

输入输出样例

输入

11 8 7 1 5 3

输出

2

说明/提示

计算得 \(X_n=X_5=8\),故\((X_n \bmod g) = (8 \bmod 3) = 2\)。

对于 \(100\%\) 的数据,\(n,m,a,c,X_0\leq 10^{18}\),\(1\leq g\leq 10^8\),\(n,m\geq 1\),\(a,c,X_0\geq 0\)。

题意

给出了一个迷惑式子,让你算出来式子的第\(n\)项,然后\(mod\ g\)的结果

分析

看到这样一个个的递推式子,一个个用\(for\)循环来推肯定不行,所以很容易就会想到要用到矩阵快速幂来求。那么我们现在的主要任务就是构造矩阵来进行乘法运算。

首先看到题目中给出的式子:

\[X_{n+1}=(aX_n+c)\ mod\ m
\]

取模运算可以暂且先不看,因为对结果没什么影响,在矩阵乘法的时候进行取模就行了。所以转化成如下式子:

\[X_{n+1}=aX_n+c
\]

那么我们就可以根据这个式子来构造矩阵。由矩阵的乘法运算为结果矩阵的\(i\)行\(j\)列为前边矩阵一个的第\(i\)行乘以另一个的第\(j\)列,所以我们可以得出如下的矩阵递推式子:

\[\left[
\begin{matrix}
X_{n-1}\\
c
\end{matrix}
\right]\times \left[
\begin{matrix}
a & 1\\
0 & 1
\end{matrix}
\right] = \left[
\begin{matrix}
X_{n}\\
c
\end{matrix}
\right]
\]

这里用\(X_{n-1}\)这一列分别乘以右边矩阵的第一第二行,得到结果的矩阵,那么我们就可以根据这个递推式子来进行矩阵快速幂。

这里乘法的运算过程如下:

\[X_{n-1}\times a+c\times 1 = X_n
\]

\[X_{n-1}\times 0+c\times 1 = c
\]

由此得到结果矩阵

这里的矩阵做乘法的时候需要用到龟速乘,不然会爆\(long\ long\)

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
struct Node{//矩阵结构体
int a[5][5];
};
int m,a,c,x0,g,n;
int ksj(int a,int b){//龟速乘
int ans = 0;
while(b){
if(b & 1)ans = (ans + a) % m;
a = (a + a) % m;
b >>= 1;
}
return ans;
}
Node Mul(Node a,Node b,int c){//矩阵乘法,记得取模
Node ans;
memset(ans.a,0,sizeof(ans.a));
for(int i=1;i<=2;++i){
for(int j=1;j<=2;++j){
for(int k=1;k<=2;++k){
ans.a[i][j] = (ans.a[i][j] + ksj(a.a[i][k],b.a[k][j])%c)%c;
}
}
}
return ans;
}
Node ans;
void qpow(Node &ans,Node b,int c){//矩阵快速幂
while(c){
if(c & 1)ans = Mul(b,ans,m);
b = Mul(b,b,m);
c >>= 1;
}
}
signed main(){
Node bas;
scanf("%lld%lld%lld%lld%lld%lld",&m,&a,&c,&x0,&n,&g);
ans.a[1][1] = x0;//初始化矩阵
ans.a[2][1] = c;
bas.a[1][1] = a;
bas.a[1][2] = 1;
bas.a[2][1] = 0;
bas.a[2][2] = 1;
qpow(ans,bas,n);
printf("%lld\n",ans.a[1][1] % g);//得答案
}

最新文章

  1. Android-环境问题
  2. Mongodb命令集合
  3. 小白学习MVC5+EF6遇到的问题一
  4. js对象详解
  5. ASCII转义字符
  6. delphi TServerSocket阻塞线程单元 实例
  7. 【BestCoder】【Round#29】
  8. POJ 1519 Digital Roots
  9. IOS常用开源库
  10. 了解Serialization
  11. 1号店Interview小结
  12. IS2009制作Oracle 静默安装包(一)感谢空白先生特许授权
  13. JAVA-面向对象2--继承
  14. iOS 创建OpenGL 环境的思考
  15. JS实现banner图轮换
  16. #417 Div2 C
  17. cent OS 7查询IP
  18. 数据库范式:1NF,2NF,3NF,BCNF浅析
  19. Hibernate进行对象的增删改查
  20. mysql网页客户端工具

热门文章

  1. GAN网络从入门教程(三)之DCGAN原理
  2. React-redux使用
  3. MYSQL 之 JDBC(十五):数据库连接池
  4. bzoj3043IncDec Sequence*
  5. /dev/mapper/VolGroup00-LogVol00 满了,根目录存储垃圾文件导致磁盘满了
  6. Apache 阿帕奇 配置运行环境
  7. python和java哪个更值得学?Python会超越Java吗?
  8. Flarum 的安装与配置
  9. Linux常用命令(学习笔记)
  10. jmeter配置原件之使用CSV Data Set Config参数化