絶滅

どうでもいい

Project Euler - Problem 230

まだ簡単なのが残ってた



Fibonacci Words

Problem 230 (日本語訳)

数字列 A, B に対して,シーケンス FA,Bを { A, B, AB, BAB, ABBAB, ... } によって定める.つまり最初の二項 A, B を除いて,各項は前二項を連結させて作られる.

さらに,DA,B(n) を FA,B において初めて n 文字以上となる要素の先頭から n 番目の数字として定義する.


例:

A = 1415926535, B = 8979323846 としたときの DA,B(35) を求める.

FA,B の最初の数項を書き出すと,
1415926535
8979323846
14159265358979323846
897932384614159265358979323846
14159265358979323846897932384614159265358979323846

したがって,DA,B(35) は 5 項目 35 番目の数字であり,それは 9 である.

A を π の小数点以下最初の 100 桁 :

14159265358979323846264338327950288419716939937510
58209749445923078164062862089986280348253421170679

B を次の 100 桁 :

82148086513282306647093844609550582231725359408128
48111745028410270193852110555964462294895493038196

としたとき,

$\sum_{n=0}^{17} 10^{n} \times D_{A,B} ((127 + 19n) \times 7^{n})$

の値はいくらか.


FA,B の k 番目の要素を FA,B,k とおき,その先頭から n 文字目を FA,B,k(n) で定める.また FA,B,k の長さを LA,B,k とする.FA,B,k の最初の数項を列挙すると,

FA,B,0 = A
FA,B,1 = B
FA,B,2 = AB
FA,B,3 = BAB
FA,B,4 = ABBAB
FA,B,5 = BABABBAB
FA,B,6 = ABBABBABABBAB
FA,B,7 = BABABBABABBABBABABBAB
FA,B,8 = ABBABBABABBABBABABBABABBABBABABBAB

2 項前の列を赤,1 項前の列を青で色付けしてある.これをじっと眺めていると FA,B,k(n) について次のことがわかる(わかってください).

  • n ≦ LA,B,k-2 なら FA,B,k(n) = FA,B,k-2(n)
  • n > LA,B,k-2 なら FA,B,k(n) = FA,B,k-1(n - LA,B,k-2)

これにより FA,B,k(n) は最終的になんらかの i ≦ LA,B,0 ( = LA,B,1 ) を用いて, FA,B,0(i) または FA,B,1(i) の形で書ける.

また,n ≦ LA,B,0 ( = LA,B,1 ) であれば,

  • FA,B,k(n) = FA,B,0(n) ( k : 偶数 )
  • FA,B,k(n) = FA,B,1(n) ( k : 奇数 )

が成り立つ.これはシーケンス FA,B の先頭のみに着目したとき A, B, A, B, A, B, … となっていることから従う.

これらを利用して DA,B(n) を求めるコードは以下.

/* L : L_{A,B,k} を格納した配列*/
char D(string A, string B, lint n, lint* L) {

    /* L[k-1] < n ≦ L[k] となる k を見つける */
    lint k = 1;
    while ( L[k] < n ) k++;

    /* n が文字列 A, B の長さ以下になるまで */
    while ( L[0] < n ) {
        
        if ( L[k - 2] < n ) {
            n = n - L[k - 2];
            k--;
        }
        else
            k -= 2;
    }

    if ( k % 2 == 0 )   // k が偶数
        return A[n - 1];
    else                // k が奇数
        return B[n - 1];
}





最後にコード全体です.10 ミリ秒以下.

#include <string>
#include <iostream>
#include <time.h>

#define LEN 100
#define SIZE 80

using namespace std;
typedef long long int lint;

lint L[SIZE];

lint ipow(lint x, lint n)
{
    lint i, ret = 1;
    for (i = 0; i < n; i++)
        ret *= x;
    return ret;
}

lint f(lint n) {
    return ipow(7, n) * (19 * n + 127);
}

char D(string A, string B, lint n, lint* L) {

    lint k = 1;
    while (L[k] < n) k++;

    while (L[0] < n) {
        if (L[k - 2] < n) {
            n = n - L[k - 2];
            k--;
        }
        else
            k -= 2;
    }

    if (k % 2 == 0) return A[n - 1];
    else          return B[n - 1];
}

void PE0230() {

    string A("1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679");
    string B("8214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196");

    L[0] = L[1] = LEN;
    for (lint i = 2; i < SIZE; i++)
        L[i] = L[i - 1] + L[i - 2];

    for (lint i = 17; i >= 0; i--)
        cout << D(A, B, f(i), L);
    cout << endl;
}

int main()
{

    clock_t start, end;
    start = clock();

    PE0230();

    end = clock();
    printf("%d msec.\n", end - start);

    return 0;
}









おまけ

f:id:my316g:20170804133238j:plain