Pisano Dönemini Bulun


20

Fibonacci dizisi 1. olan biz dizi periyodik hale gelecektir bir sabiti tarafından her dönem modüle almak durumunda her bir giriş önceki iki ve ilk iki girişlerinin toplamı olduğu bir iyi bildiği dizisidir. Örneğin, mod 7 sekansını hesaplamaya karar verirsek, aşağıdakileri elde ederiz:

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

Bunun 16 periyodu vardır. Pisano sekansı olarak adlandırılan ilgili bir sekans, a(n)modulo n hesaplandığında fibonacci sekansının periyodu olacak şekilde tanımlanır .

Görev

nVerildiğinde Fibonacci dizi modunun süresini hesaplayacak ve çıktısını alacak bir program veya işlev yazmalısınız n. Bu, Pisano dizisindeki nci terimdir.

Yalnızca aralıktaki tam sayıları desteklemelisiniz 0 < n < 2^30

Bu bir yarışmasıdır, bu nedenle kaynak kodunuzun bayt cinsinden boyutunu küçültmeyi amaçlamalısınız.

Test senaryoları

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 sınırlaması, tüm ara değerlerin 2 ^ 31'den daha az olmasını sağlayabilir, ancak yine de Pisano Dönemi'nin 32 bit işaretli bir tam sayıya sığacağını garanti etmez. (Sanırım sınırlamanızın nedeni bu mu?) Pisano Dönemleri n'den önemli ölçüde daha büyük olabilir . Örneğin, 6'nın Pisano Dönemi 24'tür. 100'ün üzerinde 10'un gücü n'den yüzde 50 daha büyük ortaya çıkar .
Iszi

3
Pigeonhole prensibi bunun f(i),f(i+1)en fazla n^2değer alabileceğini söylüyor n. Böylece, nsınırlı 2^30bir süre kadar üretebilir rüzgar kadar olabilir 2^60. Kısıtlama n <= 2^16verirdi P(n) <= 2^32.
boothby

@boothby Ne dediğini anladığımdan emin değilim ya da aynı soruyu doğru bir şekilde ele alıyorsam bile. Biraz daha açıklayabilir misiniz, belki ek linklerle? Gerekirse beni sohbete çekmekten çekinmeyin.
Iszi

2
@Izzi Gözlemleyin f(i+2) = f(i+1)+f(i), böylece periyod boyunca döngü yapan bir makinenin 'durumu' bir çift tamsayı moduyla açıklanabilir n. En fazla n^2devlet vardır, bu yüzden dönem en fazladır n^2. Ah! Wikipedia, dönemin en fazla olduğunu iddia ediyor 6n. Önemsizliğimi boşver.
boothby

Yanıtlar:


11

GolfScript ( 28 25 24 23 karakter)

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

Stdin'de girdi alır, stdout'ta bırakır (veya daha fazla işlemek istiyorsanız yığınta ...)

Bu köşe kasalarını doğru şekilde işler ( Demo ).

GolfScript programcılarının ilgisini çeken bir nokta olarak, bu, aslında denediğim diğer yaklaşımlardan daha kısa ortaya çıkan bir programla yazdığım ilk program olduğunu düşünüyorum.


7

GolfScript, 24 karakter

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

GolfScript uygulamasının sonraki tekrarı. İkinci versiyon da şimdi 1'i doğru şekilde işliyor. Oldukça uzun oldu ama belki biri bu sürümü kısaltmanın bir yolunu bulabilir. Şunları yapabilirsiniz çevrimiçi sürümü üzerinde deneyin .


Bu girişi 1doğru şekilde yapıyor mu?
Peter Taylor

@PeterTaylor Nope, o köşe vakasını test etmedi. Çizim tahtasına geri dön.
Howard

@PeterTaylor Yeni kod aynı zamanda giriş için de kullanılabilir 1- ve sadece 24 karakterdir.
Howard

4

Python, 188 132 101 95 87 karakter

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

kullanım

$ echo 10 | python pisano.py
60

Örneğin:

$ 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

Ek golf için teşekkürler beary605 !
ESultanik

Karakterlerinizi tekrar saymak isteyebilirsiniz. Yanıt sayım, yanıt sayımın altında .
DavidC

@David: Beyaz alanı mı sayıyorsunuz? Ben sadece iki kez kontrol ( catting ile wc -cve aynı numarayı almak.
ESultanik

Wolfram Research tarafından döşenmiş bir rutin kullanıyorum. Sanırım gerekli beyaz alanı sayar.
DavidC

if k>0 and s[0:k]==s[k:]:breakolarak değiştirilebilir if s and s[:k]==s[k:]:break. Yineleyiciyi kaldırarak, fordöngüyü değiştirerek ve while döngüsünün sonunda while 1:gerçekleştirerek a,b=a,a+bde önemli ölçüde azaltabilirsiniz .
Strigoides

4

piton 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

Edit: Beary ve Primo tarafından uygulanan öneriler


85:, a.append(c) -> a+=[c]döngü tek bir satıra ((n>1)>>(c in a)) -> (n>1)>>(c in a)
konabilirken

appendaslında farklı bir işlevselliğe sahiptir +=. Yine de ipuçları için teşekkürler.
scleaver

Bu durumda da aynı şekilde çalıştığını düşünüyorum.
beary605

(n>1)>>(c in a) -> (c in a)<1%n3 bayt için. Ve ekteki hakkında beary ile hemfikirim. İster bir referans ekleyin ister değerine cgenişletin , her iki şekilde de tamamen aynıdır (referansınızı hemen yok ettiğinizde ). acc
primo

Ah tamam, benim hatam a+=cyerine kullanıyorduma+=[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 bayt

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

Bu komut dosyası yanlışlıkla bildirir 2için n=1, ancak diğer tüm değerler doğrudur.

Örnek I / O, 2 (n) = 2n + 2 olduğunda solda kesilebilir bir seri:

$ 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)Tanrım, işte burada bir sömürü sömürüsü var.
Bay Llama

1

PowerShell: 98

Golf kodu:

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)}

Ungolfed, yorumlarla:

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

Notlar:

Bu komut dosyası ile maksimum güvenilir sınırın $ n için tam olarak ne olduğundan emin değilim. $ N muhtemelen oraya girmeden önce bir int32'den taşabilir. Bunun yanı sıra, üst sınırı kendim test etmedim çünkü komut dosyası için çalışma süreleri zaten sistemimde 30 saniye civarında $ n = 1e7'ye çarptı (bu sadece 2 ^ 23'ten biraz fazla). Aynı nedenle, değişkenleri bu komut dosyasının aralığını genişletmek için gerektiğinde uint32, int64 veya uint64'e yükseltmek için gereken ek sözdizimini sınamaya ve gidermeye meyilli değilim.


Örnek çıktı:

Ben döngü için başka bir sarılmış:

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

Sonra $n=$ibunun yerine ayarlayın ve komut dosyasının genel güvenilirliği hakkında fikir edinmek =read-hostiçin çıktıyı değiştirin "$i | $x". İşte çıktıdan bazıları:

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

Sidenote: Bazı Pisano Dönemlerinin n $ 'dan önemli ölçüde daha kısa olduğundan emin değilim. Bu normal mi, yoksa senaryomda bir sorun mu var? Boşver - 5'ten sonra, Fibonacci sayılarının dizideki yerlerinden çok daha hızlı büyüdüğünü hatırladım . Yani, şimdi tam anlamıyla.


1

Perl, 75 , 61 , 62 + 1 = 63

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

kullanım

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

Ungolfed

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

-nBayrak için +1 bayt . Gabriel Benamy sayesinde 13 bayt tıraş oldu.


1
$n=<>;(-6) 'dan kurtulabilir ve -nbayrağı (+1) ile değiştirebilirsiniz , sonra tüm örnekleri $nile değiştirilebilir $_. Sen kullanabilirsiniz -M5.010Kullanmak olanak sağlayan ücretsiz sayyerine komutu print(-2). Değiştirici whileifadeler, koşul (-2) çevresinde parantez gerektirmez. Bunun yerine, daha önce @{[%h]}/2bir sayacınız olabilir ve daha sonra sonunda olabilirsiniz (-2). Yerine kullanılması (-2). Bu dışarı gelmelidir ile 61 + 1 = 62 byte için, bayrak. $a++,($m,$k)=say$a-1"$m,$k"$m.$k$k=1%$_;$a++,($m,$k)=($k,($m+$k)%$_)while!$h{$m.$k}++;say$a-1-n
Gabriel Benamy

Açıkçası Perl ile sandığım kadar akıllı değilim. İpuçları için teşekkürler.
Silvio Mayolo

Perl iş parçacığında golf için İpuçları'da birçok yararlı işaretçi var ! İyi şanslar! ^^
Gabriel Benamy

İhtiyacınız - Aslında, yanılmışım "$m,$k"yerine $m.$k(+2), ancak değiştirerek 1 byte kaydedebilirsiniz while!$hiçin until$h(-1). Üzgünüm!
Gabriel Benamy

Hımm? Hangi girdi altında $m.$kbaşarısız olur? Sonunda işe yarıyor gibiydi.
Silvio Mayolo

0

Clojure, 102 bayt

Çok heyecan verici değil, geri dönene kadar formülü tekrarlıyor [1 1] (umarım bu her zaman böyledir). Birbirine yakın (f 1)olduğu için özel kullanım [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))
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.