irisruneです。ABC-F問題の壁は厚いですね。
問題
順列をどのように構築すればよいかがわかれば、順列が存在し得るかどうかも自然とわかります。あるいは小規模なケースで試してみるのもよさそうです。
package main import ( "bufio" "fmt" "os" "strconv" ) var sc *bufio.Scanner func nextInt() int { sc.Scan() i, e := strconv.Atoi(sc.Text()) if e != nil { panic(e) } return i } func main() { sc = bufio.NewScanner(os.Stdin) sc.Split(bufio.ScanWords) n, x := nextInt(), nextInt() if x <= 1 || x >= 2*n-1 { fmt.Println("No") return } values := make([]int, 0) for v := 2; v < 2*n-1; v++ { if v != x { values = append(values, v) } } fmt.Println("Yes") for i := 0; i < 2*n-1; i++ { switch { case i == n-2: fmt.Println(x) case i == n-1: switch { case x < n: fmt.Println(1) default: fmt.Println(2*n - 1) } case i == n: switch { case x < n: fmt.Println(2*n - 1) default: fmt.Println(1) } default: fmt.Println(values[0]) values = values[1:] } } }
直感的に考えると、段目では最小・最大の数(
)が存在せず、
段目では
が存在せず、…といった具合で最終的に
段目には
しか存在し得ないように思えます。
とはいえそうはならないだろうということも直感的に想像できると思います。例えばで3段目が
の場合には
段目の時点で
が存在しません。このとき、
段目は
となるので
段目は
となります。
ここで先の例について考えると、段目で同じ数が2回(連続で)現れるように構成するとその数が
段目になるということがわかります。同様に考えると、
段目の中央3か所のうち連続する2か所に同じ数が現れる場合
段目の中央3か所のうち連続する2か所に同じ数が現れることがわかります。
つまり段目の中央3か所のうち連続する2か所に
が現れるよう順列を構成すれば
段目に
が入ります。またそのような構成は
に対して存在するため、
を除く場合について順列を構成することができます。
順列の構成方法は様々だと思いますが、上記コードでは以下のようなアルゴリズムで実装しています。
- 中央の3か所以外は
を左から順番に入れる。
- 中央の3か所のうち左側は
を入れる。残り2か所は以下のように入れる。
ならば中央に
、右側に
を入れる。
ならば中央に
、右側に
を入れる。
なおのときはどのように配置しても
段目に
が入るので、上記のアルゴリズムをそのまま用いることができます。
雑記
- Difficulty1552ですが800点問題が解けました。おそらく来週金曜の記事にすると思います。