题目传送门:CF172B
题目大意
给出随机数生成函数,求得其循环节长度。
随机函数:
while(1){//修改成了 C++ 版本。
x=(a*x+b)%m;
printf("%d",x);
}
解题思路
我们发现数字会取余 m,所以生成的数字在 0 到 m 的区间内。而我们知道循环节的出现一定由一个已经出现过的数字为开始(证明见后)。
所以我们做一个数组 vis 用 vis_i 来存储数字 i 第一次出现的位置 id。如果 vis_i 为 0,证明 i 没有出现过,不管。如果不为 0,那么 i 就出现过了,输出本次的 id 减去上次的 id 即可。
证明
在输入过 a 和 b 之后,a 和 b 已经成定值,而 m 仅限制取值区间。
所以,对于任意 x, a \times x + b 的值是固定的。那么取余 m 的结果也是定值。
因为结果的值可以确定,所以出现相同数字就代表有循环节出现。
代码
#include <iostream>
#include <cstdio>
using namespace std;
int vis[100005];
int main(){
int a,m,b,x,i=1;
scanf("%d%d%d%d",&a,&b,&m,&x);
vis[x]=1;
while(1){
x=(a*x+b)%m;//题目给的代码
i++;
if(vis[x])return !printf("%d",i-vis[x]);
vis[x]=i;
}
//因为取余 m,如果有可能 0 到 m-1 都跑了一遍,它必定会出现循环节。
//所以使用 return !printf("%d",i-vis[x]); 即可。
}
Comments NOTHING