LoginSignup
0
0

More than 5 years have passed since last update.

オフラインリアルタイムどう書く E17 の実装例( Go )

Posted at

オフラインリアルタイムどう書く E17 の実装例( Go )

問題 : http://nabetani.sakura.ne.jp/hena/orde17palin/
実装リンク集 : http://qiita.com/Nabetani/items/aa15539c8dc2c610c1a0

だいぶ手こずった。

実装
package e17

import (
    "strconv"
    "strings"
)

// b の k 乗。整数版。
func powi(b, k int) int {
    if k < 0 {
        panic("k should not be negative.")
    }
    if k == 0 {
        return 1
    }
    n := powi(b, k/2)
    var r int
    if k%2 == 0 {
        r = 1
    } else {
        r = b
    }
    return n * n * r
}

// k桁の回文数の数
func pa(k, b int) int {
    if k == 1 {
        return b - 1
    }
    var mid int
    if k%2 == 1 {
        mid = b
    } else {
        mid = 1
    }
    return (powi(b, k/2) - powi(b, k/2-1)) * mid
}

// 文字列を逆順にする
func rev(s string) string {
    var b strings.Builder
    for i := len(s) - 1; 0 <= i; i-- {
        b.WriteByte(s[i])
    }
    return b.String()
}

//  0<x<m の base 進数での回文数の数
func impl(m, base int) int {
    if m <= base {
        return m - 1
    }
    s := strconv.FormatInt(int64(m), base)
    keta := len(s)
    shead := s[0 : keta/2]
    var mids []string
    if keta%2 == 1 {
        for i := 0; i < base; i++ {
            mids = append(mids, strconv.FormatInt(int64(i), base))
        }
    } else {
        mids = append(mids, "")
    }
    head64, _ := strconv.ParseInt(shead, base, 64)
    head := int(head64)
    count := 0
    for k := 1; k < keta; k++ {
        count += pa(k, base)
    }
    //keta桁の数で、前半が m の前半より小さい
    count += (head - powi(base, keta/2-1)) * len(mids)
    // keta桁の数で、前半が m の前半と等しい
    for _, mid := range mids {
        cand, _ := strconv.ParseInt(shead+mid+rev(shead), base, 64)
        if cand < int64(m) {
            count++
        }
    }
    return count
}

func solve(src string) string {
    nums := strings.Split(src, ",")
    lo, _ := strconv.Atoi(nums[0])
    hi, _ := strconv.Atoi(nums[1])
    base, _ := strconv.Atoi(nums[2])
    return strconv.Itoa(impl(hi, base) - impl(lo, base))
}
テスト
package e17

import (
    "testing"
)

func TestPowi(t *testing.T) {
    var tests = []struct {
        b, k, want int
    }{
        {10, 0, 1},
        {1, 10, 1},
        {2, 10, 1024},
        {123, 3, 123 * 123 * 123},
    }
    for _, test := range tests {
        got := powi(test.b, test.k)
        if got != test.want {
            t.Errorf("powi(%d,%d) = %d, want %d", test.b, test.k, got, test.want)
        }
    }
}

func TestRev(t *testing.T) {
    var tests = []struct {
        s, want string
    }{
        {"abc", "cba"},
        {"", ""},
        {"a", "a"},
    }
    for _, test := range tests {
        got := rev(test.s)
        if got != test.want {
            t.Errorf("rev(%s) = %s, want %s", test.s, got, test.want)
        }
    }
}

func TestImpl(t *testing.T) {
    var tests = []struct {
        k, b, want int
    }{
        {10, 10, 9},
        {12, 10, 10},
        {19, 10, 10},
        {23, 10, 11},
        {100, 10, 18},
        {102, 10, 19},
    }
    for _, test := range tests {
        got := impl(test.k, test.b)
        if got != test.want {
            t.Errorf("impl(%d,%d) = %d, want %d", test.k, test.b, got, test.want)
        }
    }
}

func Test(t *testing.T) {
    var tests = []struct {
        name  string
        input string
        want  string
    }{
        {"0", "12,34,5", "5"},
        {"1", "10,11,10", "0"},
        {"2", "1,100,3", "18"},
        {"3", "11,12,10", "1"},
        // 中略
        {"33", "2099642384,2789567569,6", "14787"},
    }
    for _, test := range tests {
        got := solve(test.input)
        if got != test.want {
            t.Errorf("%v: solve(%q)=%q, want %q\n", test.name, test.input, got, test.want)
        }
    }
}

いろいろ手こずった。
ruby なら n=str.to_i(base) と書くところを、

go
n64, _ := strconv.ParseInt(str, base, 64)
n := int(n64)

と書かざるを得ないところとか、思考が遮られる感じ。

整数用指数関数( powi )を用意したり。

実行は一瞬でとても速いけど、ruby でも一瞬なので、大差ない。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0