本文参考资料:http://hi.baidu.com/bnjyjncwbdbjnzr/item/1f997cfdd225d5d143c36a58

题意:一个生成随机数的函数,

Seed[x+1] = ( seed[x] + STEP ) % MOD

输入step和mod,问能否生成0~MOD-1之间所有的数,是Good Choice,否则Bad Choice

题意其实就是:给出S和M,求0*S%M,1*S%M,2*S%M......(M-1)*S%M能否组成一个集合包含0.1.。。。M-1;(这个是原题意改造而来);

算法:判断两个数是否互质;or 暴力解决

其实暴力完全可以解决这个问题(⊙﹏⊙b),只是其中用数学方法更加高效,巧妙;

下面证明“如果SM互质则满足题意”:

设G=gcd(S,M);则S=A*G,M=B*G;

另设X=K*S%M=K*S-T*M(T为整数,满足X属于0到M-1。其实就是说T是K*S除以M的商。);

X=K*A*G-T*B*G;因此取余后的整数一定是G的倍数。

所以,上述要求证明的命题其实就是要证明:G只能取1才能满足条件;

(个人感觉上述论证就是废话呵呵——S和M互质不就是gcd(S,M)==1吗?)

(下面继续刚才的证明)

充分性的证明:(即当S与M互质,则0到M-1的S倍对M取余一定能遍历0到M-1)

只需证明的是,该余数中两两之间互不相等;

假设k*S和b*S对M取余相等(k和b∈[0,M),并且k和b不等);

则k*S=q1*M+r≡q2*M+r=b*S     <==>      (k-b)*S=M*(q1-q2);

因为题设S与M互质,再由上式子可得M|(k-b),这与k和b∈[0,M),并且k和b不等矛盾;

因此题目命题得证。

另外,偶然看到一个很牛叉的辗转相除法;

int gcd(int a,int b)

{

while(b) b^=a^=b^=a%=b;

return a;

}

此代码,很好很强大;把涉及位运算的交换的程序加入,便到得这段简洁高效的代码;

注:A和B;经过A^=B^=A^=B,结果就得到A和B的交换;

 #include<stdio.h>
long gcd(long a,long b);
int main()
{
long step,mod;
while(scanf("%ld%ld",&step,&mod)!=EOF)
{
if(gcd(step,mod)==) printf("%10d%10d Good Choice\n\n",step,mod);
else printf("%10d%10d Bad Choice\n\n",step,mod);
}
return ;
}
long gcd(long a,long b)
{
long c;
if(b==) return a;
c=a%b;
while(c)
{
a=b;
b=c;
c=a%b;
}
return b;
}

下面是其他网友对该问题的论述:(感觉没有上面的讲的清楚,可以直接忽略)

以数论的观点解释 poj1597 && 更相减损术

http://blog.163.com/jiazheng2222@126/blog/static/1696323832009513104450808/

可以想象成有一个人从起点0处绕着一个圈长为mod个单位“跳步”,每跳一次必须跳step个单位(也就是可不能出现在i*step<pos<(i+1)*step的位置),而至少跳mod次恰好回到起点的话,就是Good Choice,如果在第mod次前就恰好到达起点则为Bad Choice

而我们知道,回到起点把所需的最短时间即是step和mod的最小公倍数,而若为Good Choice,显然最短时间又等于step*mod,由数论的知识gcd(step,mod)=step*mod/(step和mod的最小公倍数)=1

bool check(long step,long mod)
{
    long m=step>mod?step:mod;
    long n=step>mod?mod:step;
    long q=1;

while(q!=0)
    {
        q=m-n;
        m=n>q?n:q;
        n=n>q?q:n;

}
    if(m==1)
        return true;
    else
        return false;
}

http://hi.baidu.com/sjzezoi/item/6a3a71ccab9fee32b67a24fa

题意:一个生成随机数的函数,

Seed[x+1] = ( seed[x] + STEP ) % MOD

问能不能生成0~MOD-1之间所有的数,是Good Choice,否则Bad Choice

此题可以暴力模拟,但正解应该是gcd(STEP,MOD)==1

设G=gcd(a,b),于是有a=A*G,b=B*G(1<=A,B,gcd(A,B)=1) 对于a的多次加可以看成K*a(1<=k),转化成(K*a)%b的所有结果能否表示成0..b-1中的所有数,假(K*a)%b=M,M=K*a-W*b(W为使M>0的最大整数),M=K*A*G-W*B*G M%G==0,既结果是G的倍数,如果想取得0..b-1中的所有数,那么必须G=1才可能..

(代码仅供参考和学习,请不要直接粘贴刷AC数,期待你写出更好的代码)贡献一次PE

暴力:

#include<cstdio>

#include<cstring>

int a,b;

bool vis[100010];

int main()

{

while(scanf("%d%d",&a,&b)+1)

{

memset(vis,0,sizeof vis);

int cnt=0,now=0;

while(cnt<b)

{

if(vis[now]) break;

vis[now]=1;

now=(now+a)%b;

cnt++;

}

if(cnt==b) printf("%10d%10d    Good Choice\n\n",a,b);

else printf("%10d%10d    Bad Choice\n\n",a,b);

}

return 0;

}

正解:

#include<cstdio>

int a,b;

inline int gcd(int x,int y)

{

if(!y) return x;

return gcd(y,x%y);

}

int main()

{

while(scanf("%d%d",&a,&b)==1)

{

if(gcd(a,b)==1) printf("%10d%10d    Good Choice\n\n",a,b);

else printf("%10d%10d    Bad Choice\n\n",a,b);

}

return 0;

}

http://hi.baidu.com/zhuangxie1013/item/cc5a130b05e77ad573e676b0

这题其实是道数论题,但我把它当作模拟题来做了,虽然做出来了,但所用的空间和时间也大的吓人,此题输出时需要注意:输出格式为printf("%10d%10d    Bad
Choice\n\n",step,mod);即第二个数和Bad Choice之间有4个空格,下面是我模拟出来的程序:

#include<iostream>
#include<set>
#include<algorithm>
#include<cstdlib>
using namespace std;

int main()
{
int step,mod,i,temp;
set<int>s;
while(scanf("%d %d",&step,&mod)!=EOF)
{
   temp=0;
   s.insert(temp);
   for(i=1;i<mod;i++)
   {
    temp=(temp+step)%mod;
    s.insert(temp);
   
if(s.size()!=(i+1))                                                                
//出现重复元素
    {
     printf("%10d%10d    Bad
Choice\n\n",step,mod);
     break;
    }

}
   temp=(temp+step)%mod;
   if(temp==0&&s.size()==mod)
    printf("%10d%10d    Good
Choice\n\n",step,mod);
     s.clear();
}
system("pause");
return 0;
}

看了别人的方法,讲的都是数论,所以将其转载:

题目的意思就是一个生成随机数的函数,

Seed[x+1] = ( seed[x]
+ STEP ) % MOD

其中seed就是我们生成出来的随机数,至于seed[0]是哪个数并不重要,后面会证明。STEP就是我们每次往前一个所加的值,再module上MOD得到下一个随机数。

判断这个随机生成函数的好坏的依据是如果能够产生0~MOD-1内的所有数,就是一个好的,否则坏。

我们知道了同余的特性,便可以假设在k步之后,生成的seed[k] = seed[0],所以由此有

Seed[k] = ( seed[0]
+ STEP*k ) % MOD

那么,

STEP * k = MOD

而我们如果要生产MOD个数,必须使k≥MOD,而且k不可能大于MOD,因为这个条件下生成的数又开始重复,所以k=MOD;在前面的条件下,如果STEP和MOD有大于1的公约数例如d,那么会有STEP*(k/d) = MOD,这就是一个循环了,只会产生k/d<MOD个随机数。

结论:iff gcd(STEP, MOD) == 1, good choice

poj 1597 Uniform Generator【生成指定范围内所有随机数】的更多相关文章

  1. JS生成指定范围内的随机数(支持随机小数)

    直接需要函数的话,直接到文章的最后面找. ============================================================= 转载:https://www.cn ...

  2. 【转载】C#使用Random类来生成指定范围内的随机数

    C#的程序应用的开发中,可以使用Random随机数类的对象来生成相应的随机数,通过Random随机数对象生成随机数的时候,支持设置随机数的最小值和最大值,例如可以指定生成1到1000范围内的随机数.R ...

  3. 关于 Math.random()生成指定范围内的随机数的公式推导

    关于 Math.random()生成指定范围内的随机数的公式推导 在 java 中,用于生成随机数的 Math 方法 random()只能生成 0-1 之间的随机数,而对于生成指定区间,例如 a-b ...

  4. javascript 生成指定范围内的随机数

    js 生成任意2个区间内的随机整数,js 生成两个数之间的随机数 function random(m,n) { return Math.floor(Math.random() * (n - m)) + ...

  5. shell生成指定范围内的随机数

    #!/bin/bash read -p "请输入起始数:" min read -p "请输入终止数:" max if [ $min -gt $max ] the ...

  6. SQL - 生成指定范围内的随机数

    今天按照公司需求,需要做一个sql作业来对数据库定时触发,其中有个难点,就是在sql中需要在1-n中随机出来一个结果. google了半天,找到一个比较好的方式. 写下这个sql: DECLARE @ ...

  7. 【转】 SQL - 生成指定范围内的随机数

    DECLARE @Result INT DECLARE @Upper INT DECLARE @Lower INT SET @Lower = 1 SET @Upper = 10 SELECT @Res ...

  8. js中Math.random()生成指定范围数值的随机数

    http://www.111cn.net/wy/js-ajax/57062.htm Math.random() 这个方法相信大家都知道,是用来生成随机数的.不过一般的参考手册时却没有说明如何用这个方法 ...

  9. C#生成指定范围内的不重复随机数

    C#生成指定范围内的不重复随机数 // Number随机数个数 // minNum随机数下限 // maxNum随机数上限 public int[] GetRandomArray(int Number ...

随机推荐

  1. LeetCode----Word Ladder 2

    Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from ...

  2. java课程三课堂例子验证

    1.ClassAndObjectTest.java 验证截图: 2.ObjectEquals.java 运行截图: 3.InitializeBlockDemo.java   Java进行初始化的地方有 ...

  3. jQuery中.parent和.parents的区别

    .parent(selector) 获得当前匹配元素集合中每个元素的父元素,由选择器筛选(可选). .parents(selector) 获得当前匹配元素集合中每个元素的祖先元素,由选择器筛选(可选) ...

  4. Java 集合深入理解(11):LinkedList

    点击查看 Java 集合框架深入理解 系列, - ( ゜- ゜)つロ 乾杯~ 今天心情鱼肚白,来学学 LinkedList 吧! 日常开发中,保存一组数据使用的最多的就是 ArrayList, 其次就 ...

  5. 解决spring配置中的bean类型的问题:BeanNotOfRequiredTypeException

    解决spring配置中的bean类型的问题:BeanNotOfRequiredTypeException这个问题出现的原因:一般在使用annotation的方式注入spring的bean 出现的,具体 ...

  6. Intent传输包含对象的List集合

    这个其实也比较简单,我也是参考了网上的一些例子,不过我写的这个小例子亲测可用.用实现Serializable接口的方式实现. 就是说,你的list集合中的对象必须先实现Serializable接口,其 ...

  7. oledb 写入 office2010 以及发布到iis 遇到的奇怪问题总结

    这段时间在做Excel 导出升级,把之前的office2003 升级到 2010导出. 一 利用oledb 写入 Excel 2010 的时候,怎么也打不开文件,最后调查的原因是 需要修改连接字符串: ...

  8. SQLITE LIMIT

    sqlite> create table t_user(userid int,username varchar(20)); sqlite> insert into t_user value ...

  9. scala言语基础学习十二

  10. 课堂所讲整理:HTML--8Window.document对象

    1.Window.document对象 一.找到元素: docunment.getElementById("id"):根据id找,最多找一个:    var a =docunmen ...