ABC170_Cにて
ABC170のC問題を解き、自信満々に提出したときの話。
3AC,12WA。入力例にあげられているサンプルも2つ、WAをだしていた。
「提出する前に確認したはずなのにどうして」と再度確認するも、サンプルは正答できている。
手元と提出したもので結果が変わっている
試しに「コードテスト」のページで実行してみる。
(今回の件に関係ない処理を省略した、入力を受け取って出力するだけのコード)
// 警告: このコードを長時間直視しないでください。 package main import ( "bufio" "fmt" "os" ) func main() { scanner := bufio.NewScanner(os.Stdin) var n int scanner.Scan() fmt.Sscan(scanner.Text(), &n) p := make([]int, n) for i := range p { fmt.Scan(&p[i]) } fmt.Printf(p) } /* input 5 4 7 10 6 5 */
「これは酷い」と思うかもしれない。というか改めて見ると自分でも引くくらい酷い。
コードがぐちゃぐちゃなのは許してほしい。
n
を受け取る時点では「scanner
でサッと読み込もう」としたものの、
[]int
をscaner
で受け取るのが面倒で結局fmt.Scan
を使ってる。
(scanner
だと、[]string
を[]int
に変換する必要がある)
普通に書いてたらこんな統一性のないことにはならないだろう。
ただ、私は既に書いてあるn
の受け取りを統一するのが面倒だった。
inputの値をセットして、実行してみる。
手元で出力されるのは[4 7 10 6 5]
。しかし、コードテストでは[0 0 0 0 0]
だった。
ちなみにこれは2つの入力受け取りをscanner
かfmt.Scan
のどちらかに統一することで解決できる。
ぐちゃぐちゃだからこそ今回の事件(?)が起きた。
なぜ結果が変わるのか
最初に疑うのはバージョンの壁。
試してみる。
$ go version go version go1.14.4 linux/amd64
ローカルのバージョンは1.14.4。
package main import ( "fmt" "runtime" ) func main() { fmt.Println(runtime.Version()) } /* output go1.14.1 */
AtCoder上のバージョンは1.14.1。ちょっとだけ違う。
一応試す。
$ goenv install -l (snip) 1.14.1 1.14.2 1.14.3 1.14.4
1.14.1があることを確認する。
$ goenv install 1.14.1 $ goenv global 1.14.1
1.14.1をインストール、バージョンを切り替える。
goenv rehash
とかで反映できるっぽいですが、私はBashを開き直しました。
$ go version go version go1.14.1 linux/amd64
しっかりバージョンが変わっている。さて、実行してみよう。
$ go run main.go 5 4 7 10 6 5 [4 7 10 6 5]
ちゃんと受け取れる。
ふむ。。。。
「じゃあ実行方法が違うのかな」となり、
とあるサイトで競プロ的なことをしたときに制約として以下のようなことが書いてあったことを思い出した。
提出されたコードは以下のように実行されます。
go run main.go < input.txt
(go run
ではなかったかも。詳しくは覚えてない)
AtCoder上でも同じかどうかはわからないが、これをローカルで試してみる。
$ cat > input.txt 5 4 7 10 6 5 $ go run main.go < input.txt [0 0 0 0 0]
ビンゴ。
2列目の入力が受け取れなくなってる。
これが今回の原因。
あとがき
今回のようなぐちゃぐちゃなコードでも書かない限り遭遇しないと思うので、綺麗なコードを書こう。