寻找皮萨诺时期


20

的斐波那契序列是众所周知的序列,其中每个条目的前两个与前两项的总和是1。如果我们把每学期的模一个恒定的顺序将成为周期性的。例如,如果我们决定计算序列mod 7,我们将得到以下结果:

1 1 2 3 5 1 6 0 6 6 5 4 2 6 1 0 1 1 ...

它的周期为16。定义了一个相关序列,称为Pisano序列,使得该序列是a(n)模数为n时斐波纳契序列的周期。

任务

您应该编写一个程序或函数,给定的程序或函数n将计算并输出Fibonacci序列mod的周期n。那是Pisano序列中的第n项。

您只能在范围内支持整数 0 < n < 2^30

这是一场竞赛,因此您应努力使按字节计分的源代码的大小最小化。

测试用例

1  -> 1
2  -> 3
3  -> 8
4  -> 6
5  -> 20
6  -> 24
7  -> 16
8  -> 12
9  -> 24
10 -> 60
11 -> 10
12 -> 24

3
限制为2 ^ 30可以确保所有中间值都小于2 ^ 31,但仍不能保证Pisano周期适合32位有符号整数。(我相信这是你的限制的原因是什么?)皮萨诺周期可以显著比他们更大的ñ。例如,皮萨诺(Pisano)周期6是24。100之上的10的幂比n大50%。
— Iszi 2013年

3
Pigeonhole原理说f(i),f(i+1)最多可以取n^2mod的值n。因此,n限制为2^30可以产生最多的周期2^60。限制n <= 2^16会给P(n) <= 2^32。
— 展位,2013年

@boothby我不太确定我是否理解您的意思,或者它是否能够正确解决我所遇到的相同问题。您能否进一步解释一下,也许还有其他链接?如有需要,请随时与我聊天。
— Iszi 2013年

2
@Iszi观察到这一点f(i+2) = f(i+1)+f(i),因此可以使用一对整数mod来描述该周期内机器循环的“状态” n。最多有n^2州,所以期间最多n^2。哦! 维基百科声称这个时期最多6n。别管我的琐事。
— 2013年

Answers:


11

GolfScript(28 25 24 23个字符)

~1.{(2$+}{.@+2$%}/+\-,)

在stdin中接受输入,将其保留在stdout(或堆栈,如果您想进一步处理...)

这样可以正确处理极端情况(Demo)。

作为GolfScript程序员的兴趣点,我认为这是我编写的第一个程序,实际上比我尝试的其他方法更短。


7

GolfScript,24个字符

~:&1.{.2$+&%.2$(|}do](-,

GolfScript实现的下一个迭代。现在,第二个版本也可以正确处理1。它变得相当长,但也许有人可以找到缩短此版本的方法。您可以在线尝试以上版本。


这样可以1正确处理输入吗?
— 彼得·泰勒

@PeterTaylor Nope,没有测试那个极端情况。回到绘图板。
— 霍华德

@PeterTaylor新代码也可用于输入1-仍然只有24个字符。
— 霍华德

4

Python,第188 132 101 95 87个字符

n=input()
s=[]
a=k=0
b=1
while s[:k]!=s[k:]or k<1:s+=[a%n];k=len(s)/2;a,b=b,a+b
print k

用法

$ echo 10 | python pisano.py
60

例如:

$ for i in {1..50}; do; echo $i | python pisano.py; done
1
3
8
6
20
24
16
12
24
60
10
24
28
48
40
24
36
24
18
60
16
30
48
24
100
84
72
48
14
120
30
48
40
36
80
24
76
18
56
60
40
48
88
30
120
48
32
24
112
300

谢谢beary605额外的打高尔夫球!
— ESultanik

您可能想要再次计算字符数。我的回应数低于您的回应数。
— DavidC 2012年

@David:您在计算空格吗?我只是双重检查(由cat婷wc -c,我也得到了相同的编号。
— ESultanik

我使用Wolfram Research提供的例程。我认为,它计算出必要的空白。
— DavidC 2012年

if k>0 and s[0:k]==s[k:]:break可以更改为if s and s[:k]==s[k:]:break。您还可以通过删除迭代器,将for循环更改为while 1:,并a,b=a,a+b在while循环结束时执行操作,从而显着减少开销。
— Strigoides 2012年

4

蟒蛇 90 85 96 94 90 82

n=input();c=[1,1];a=[]
while(c in a)<1%n:a+=[c];c=[c[1],sum(c)%n]
print len(a)or 1

编辑:由贝里和普里莫实施建议


85 :a.append(c) -> a+=[c],而循环可以放在一行上,((n>1)>>(c in a)) -> (n>1)>>(c in a)
— beary605

append实际上与的功能不同+=。谢谢你的提示。
— scleaver

我认为在这种情况下,它的工作方式相同。
— beary605

(n>1)>>(c in a) -> (c in a)<1%n3个字节 我同意beary关于附录的内容。无论是将引用附加到c,还是扩展a的值c,两种方法都完全相同(因为c无论如何您都会立即销毁引用)。
— 2012年

嗯,我的错误是我使用的a+=c不是a+=[c]
— scleaver

2

Mathematica 73

p = {1, 0}; j = 0; q = p;
While[j++; s = Mod[Plus @@ p, n]; p = RotateLeft@p; p[[2]] = s; p != q]; j

2

PHP- 61 57字节

<?for(;1<$a.$b=+$a+$a=!$i+++$b%$n+=fgets(STDIN););echo$i;

这个脚本会错误地报告2了n=1,但所有其他的值是否正确。

样本I / O,这是一个左截断序列,其中π(n)= 2n + 2

$ echo 3 | php pisano.php
8
$ echo 13 | php pisano.php
28
$ echo 313 | php pisano.php
628
$ echo 3313 | php pisano.php
6628
$ echo 43313 | php pisano.php
86628
$ echo 543313 | php pisano.php
1086628
$ echo 4543313 | php pisano.php
9086628
$ echo 24543313 | php pisano.php
49086628

1
1<$a.$b=+$a+$a=!$i+++$b%$n+=fgets(STDIN)哦,天哪,这就是操作开发的顺序。
— 拉马先生2012年

1

的PowerShell:98

高尔夫代码:

for($a,$b=0,(1%($n=read-host))){$x++;if($a+$b-eq0-or("$a$b"-eq10)){$x;break}$a,$b=$b,(($a+$b)%$n)}

取消评论,并附有评论:

for
(
    # Start with $a as zero, and $b as 1%$n.
    # Setting $b like this at the start helps catch the exceptional case where $n=1.
    $a,$b=0,(1%
    (
        # Grab user input for n.
        $n=read-host
    ))
)
{
    # Increasing the counter ($x) and testing for the end of the period at the start ensures proper output for $n=1.
    $x++;

    # Test to see if we've found the end of the Pisano Period.
    if
    (
        # The first part catches $n=1, since $a and $b will both be zero at this point.
        $a+$b-eq0-or
        (
            # A shorter way of testing $a-eq1-and$b-eq0, which is the end of a "normal" Pisano Period.
            "$a$b"-eq10
        )
    )
    {
        # Pisano Period has reached its end. Output $x and get out of the loop.
        $x;break
    }

    # Pisano Period still continues, perform operation to calculate next number.
    # Works pretty much like a Fibonacci sequence, but uses ($a+$b)%$n for the new $b instead.
    # This takes advantage of the fact we don't really need to track the actual Fibonacci numbers, just the Fibonacci pattern of %$n.
    $a,$b=$b,(($a+$b)%$n)
}

# Variable cleanup - not included in golfed code.
rv n,a,b,x

笔记:

我不确定使用此脚本对$ n的最大可靠限制是多少。它可能小于2 ^ 30,因为$ x可能在$ n到达那里之前溢出int32。除此之外,我自己还没有测试上限,因为脚本的运行时间在我的系统上已经达到30秒,价格为$ n = 1e7(仅比2 ^ 23多一点)。出于相同的原因,我不会很快倾向于对可能需要的其他语法进行测试和故障排除,以将变量升级到uint32,int64或uint64,以便扩展此脚本的范围。


样本输出:

我将其包装在另一个for循环中:

for($i=1;;$i++)

然后设置$n=$i代替=read-host,然后更改输出以"$i | $x"了解脚本的一般可靠性。这是一些输出:

1 | 1
2 | 3
3 | 8
4 | 6
5 | 20
6 | 24
7 | 16
8 | 12
9 | 24
10 | 60
11 | 10
12 | 24
13 | 28
14 | 48
15 | 40
16 | 24
17 | 36
18 | 24
19 | 18
20 | 60

...

9990 | 6840
9991 | 10192
9992 | 624
9993 | 4440
9994 | 1584
9995 | 6660
9996 | 1008
9997 | 1344
9998 | 4998
9999 | 600
10000 | 15000
10001 | 10212
10002 | 3336
10003 | 5712
10004 | 120
10005 | 1680
10006 | 10008
10007 | 20016
10008 | 552
10009 | 3336
10010 | 1680

边注: 我不太确定Pisano周期比$ n短得多。这是正常现象,还是我的脚本有问题?没关系-我只是记得,5后,斐波那契数迅速成为很多比他们的顺序发生大。因此,这现在很有意义。


1

Perl,75岁,61,62 + 1 = 63

$k=1%$_;$a++,($m,$k)=($k,($m+$k)%$_)until$h{"$m,$k"}++;say$a-1

用法

$ echo 8 | perl -n -M5.010 ./pisano.pl
12

不打高尔夫球

$k = 1 % $_;
$a++, ($m, $k) = ($k, ($m + $k) % $_) until $h{"$m,$k"}++;
say $a - 1

+1字节的-n标志。感谢Gabriel Benamy削减了13个字节。


1
您可以摆脱$n=<>;(-6)并将其替换为-n标志(+1),然后$n可以将所有实例替换为$_。您可以使用-M5.010免费,使用该say命令代替print(-2)。修饰符while语句不需要在条件(-2)周围加括号。代替@{[%h]}/2,您可以$a++,在前面有一个计数器($m,$k)=,然后say$a-1在末尾(-2)。而不是"$m,$k"使用$m.$k(-2)。对于61 + 1 = 62字节,这应该$k=1%$_;$a++,($m,$k)=($k,($m+$k)%$_)while!$h{$m.$k}++;say$a-1与-n标志一起出现。
— 加布里埃尔·贝纳米

显然,我对Perl的了解不如我以前想象的那么聪明。感谢您的提示。
— 西尔维奥·马约洛

在Perl线程中打高尔夫球的技巧中有很多有用的指针!祝好运!^^
— Gabriel Benamy '16

其实,我错了-你需要"$m,$k"的不是$m.$k,(+2),但是可以通过更改保存1个字节while!$h到until$h(-1)。抱歉!
— 加布里埃尔·贝纳米

嗯?在什么输入下$m.$k失败?它似乎对我有效。
— 西尔维奥·马约洛

0

Clojure,102字节

不太令人兴奋,请迭代公式,直到我们返回[1 1](我希望情况总是如此)。(f 1)收敛到时的特殊处理[0 0]。

#(if(< % 2)1(+(count(take-while(fn[v](not=[1 1]v))(rest(iterate(fn[[a b]][b(mod(+ a b)%)])[1 1]))))1))
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.