피사노 시대 찾기


20

피보나치 순서는 1. 있습니다 우리는 순서가 주기적 될 것이다 일정한 각 용어의 모듈을 경우 각 항목은 이전 두와 처음 두 항목의 합계 인 잘 알고 순서입니다. 예를 들어, 시퀀스 mod 7을 계산하기로 결정했다면 다음과 같은 결과가 나타납니다.

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

이것은 16의주기를 갖는다. 피사노 서열 이라 불리는 관련 서열 a(n)은 모듈로 n을 계산할 때 피보나치 서열 의 주기가되도록 정의 된다.

태스크

주어진 n경우 피보나치 시퀀스 모드의주기를 계산하고 출력 하는 프로그램이나 함수를 작성해야합니다 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보다 작을 수 있지만 피사노 기간이 32 비트 부호있는 정수 내에 들어가는 것은 아닙니다. (나는 그것이 당신의 제한 이유라고 생각합니까?) 피사노 기간은 그들의 n 보다 상당히 클 수 있습니다 . 예를 들어, 6의 피사노주기는 24입니다. 100보다 큰 10의 거듭 제곱은 n 보다 50 % 더 큽니다 .
Iszi

3
비둘기 구멍 원리는 f(i),f(i+1)최대 n^2값 mod를 취할 수 있다고 말합니다 n. 따라서, 최대 기간을 생산할 수있는 것으로 n제한 2^30됩니다 2^60. 제한 n <= 2^16하면 줄 것이다 P(n) <= 2^32.
boothby

@boothby 나는 당신이 무슨 말을하는지 이해하지 못하거나 그것이 동일한 문제를 올바르게 해결하고 있는지 확실하지 않습니다. 추가 링크를 통해 조금 더 설명해 주시겠습니까? 필요한 경우 언제든지 채팅에 참여하십시오.
Iszi

2
@Iszi f(i+2) = f(i+1)+f(i)주기를 반복하는 머신의 '상태'는 정수 mod 쌍으로 설명 할 수 있습니다 n. 대부분의 n^2주가 있으므로 기간은 최대 n^2입니다. 오! 위키 백과는 그 기간이 최대라고 주장한다 6n. 내 사소한 생각하지 마십시오.
boothby

답변:


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, 그 코너 케이스를 테스트하지 않았습니다. 드로잉 보드로 돌아갑니다.
Howard

@PeterTaylor 새 코드는 입력에도 작동 1하며 여전히 24 자입니다.
Howard

4

파이썬 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

@David : 공백을 세고 있습니까? 방금 catwc -c
재확인

저는 Wolfram Research에서 제공하는 루틴을 사용합니다. 필요한 공백을 계산합니다.
DavidC

if k>0 and s[0:k]==s[k:]:break로 변경할 수 있습니다 if s and s[:k]==s[k:]:break. 반복자를 제거하고 for루프를로 변경 한 후 while 루프의 끝에서 while 1:수행 a,b=a,a+b하여 크게 줄일 수도 있습니다 .
Strigoides

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

편집 : beary 및 primo에 의해 제안 된 구현


85 : a.append(c) -> a+=[c], while 루프를 한 줄에 넣을 수 있습니다((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확장 하든 관계없이 ( 어쨌든 참조를 즉시 파괴하므로) 어느 쪽이든 동일합니다 . acc
primo

아 그래, 내 실수는 내가 a+=c대신 사용하고 있었다a+=[c]
scleaver

2

매스 매 티카 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)세상에, 그것은 약간의 작업 착취 순서입니다.
Mr. Llama

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에 대한 최대 신뢰할 수있는 제한이 정확히 무엇인지 잘 모르겠습니다. $ n은 $ n에 도달하기 전에 int32를 오버플로 할 수 있기 때문에 2 ^ 30보다 적을 수 있습니다. 게다가 스크립트의 실행 시간이 이미 내 시스템에서 $ n = 1e7 (2 ^ 23을 약간 넘음) 동안 30 초 정도 걸렸기 때문에 상한을 직접 테스트하지 않았습니다. 같은 이유로이 스크립트의 범위를 확장하기 위해 필요한 경우 변수를 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

펄, 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

-n플래그의 경우 +1 바이트 Gabriel Benamy 덕분에 13 바이트를 줄였습니다.


1
$n=<>;(-6)을 제거 하고 -n플래그 (+1)로 바꾸면의 모든 인스턴스를로 $n바꿀 수 있습니다 $_. -M5.010무료로 사용할 수 있으므로 (-2) say대신 명령 을 사용할 수 있습니다 print. 수정 자 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플래그 와 함께 나옵니다 .
가브리엘 베 나미

내가 생각했던 것보다 분명히 나는 ​​펄에게 영리하지 않다. 팁 주셔서 감사합니다.
Silvio Mayolo

Perl 스레드의 골프 팁 에 유용한 포인터가 많이 있습니다 ! 행운을 빕니다! ^^
가브리엘 베 나미

실제로, 나는 틀 렸습니다- "$m,$k"대신 $m.$k(+2) 대신 필요 하지만 (-1) 으로 변경 while!$h하여 1 바이트를 절약 할 수 있습니다 until$h. 죄송합니다!
가브리엘 베 나미

흠? 어떤 입력에서 $m.$k실패합니까? 그것은 나의 끝에 작동하는 것 같았다.
Silvio Mayolo

0

클로저, 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))
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.