Problem:
E: 鬼畜ババ抜き - Unbalanced Old Maid -

物語

高坂さんと園田さんと南さんは子供の頃からの仲良し3人組だ。3人は沖縄に修学旅行に行くも、台風が来てしまい、海で遊ぶことができないのでババ抜きをすることにした。

園田さんは勝負事には強いが、ポーカーフェイスが苦手なため、自分のカードが引かれるときに無意識にかわいらしい顔芸を披露してしまう。園田さんを愛して止まない高坂さんと南さんは、園田さんの顔芸を見るだけで園田さんの手札が分かってしまうため、園田さんのカードを引くときは、自分が有利になるように引くことができる。
一方、高坂さんと南さんは特に顔芸をしたりはしないので、手札がばれることはない。 よって、高坂さんと南さんのカードを引く人はそれぞれ、高坂さんと南さんが持っているカードの中から等確率で1枚引く。

どう考えても不利な園田さんは、ババ抜きでなかなか勝てないことに違和感を覚えている。 使用するカードの種類数nと初期の手札が与えられたとき、園田さんが負けとならない確率を求めてあげよう。

問題文

高坂さん、園田さん、南さんの3人は、以下の状況でババ抜きを行う。

使用するカードは、1からnまでの整数が書かれたn種類のカードそれぞれ4枚ずつとジョーカー1枚の合計4n+1枚である。

最初の手札が与えられたとき、3人はそれぞれ自分の手札に同一の整数が書かれたカードのペア（2枚組）があるならば、そのようなペアを全て捨てる。

3人は「高坂さんが南さんの手札からカードを引く」、「園田さんが高坂さんの手札からカードを引く」「南さんが園田さんの手札からカードを引く」という順番（ターン）で以下の操作を繰り返す。（このババ抜きでは、カードを引いた人が、次に引かれるというルールであることに注意せよ。）

一人がジョーカーのみを持ち、その人以外の2人の手札が空のとき、ババ抜きは終了し、ジョーカーを持っている人が負けとなる。

カードを引く順番の人の手札が空のとき、ターンを次の人とし、1.に戻る。

そうでなければ、カードを引く順番の人は決められた相手からカードを1枚引く。ただし、相手の手札が空のとき、まだ残っているもう1人からカードを引く。

引いたカードと同じ整数が書かれたカードがカードを引いた人の手札にあれば、その2枚を捨てる。

ターンを次の人とし、1.へ戻る。

ただし、園田さんのカードを引く人（南さんか高坂さん）は、以下の戦略でカード引く。

もし自分のカードと園田さんのカードで同じ整数が書かれたカードがあれば、それらのうち最小の整数が書かれたカードを引く

そうでないとき、園田さんがジョーカーでないカードを持っていれば、それらのうち最小の整数が書かれたカードを引く

そうでないなら、園田さんはジョーカーしか持っていないので、ジョーカーを引く

高坂さんと南さんのカードを引く人は、それぞれ高坂さんと南さんが持っているカードの中から等確率で1枚引く。

使用するカードの種類数nと3人の初期の手札が与えられたとき、園田さんが負けとならない確率を求めてあげよう。

入力形式

入力は4行からなり、以下の形式で与えられる。

n
m_1 c_{1,1} ... c_{1,m_1}
m_2 c_{2,1} ... c_{2,m_2}
m_3 c_{3,1} ... c_{3,m_3}

1行目にジョーカー以外のカードの種類数nが与えられる。
続く入力は3行からなり、2行目に高坂さんの手札、3行目に園田さんの手札、4行目に南さんの手札の情報が与えられる。
i+1 (1 ≤ i ≤ 3)行目では行頭に手持ちの枚数m_i、続けて手持ちのカードを表すm_i個の整数c_{i,j} (1 ≤ j ≤ m_i)が空白区切りで与えられる。 0はジョーカー、1からnはカードに書かれた整数を表す。

制約

1 ≤ n ≤ 100

m_1+m_2+m_3 = 4n+1

3人の手札で0はちょうど1つ、1からnはちょうど4回ずつ現れる

0 ≤ c_{i,j} ≤ n (1 ≤ i ≤ 3, 1 ≤ j ≤ m_i)

出力形式

園田さんが負けとならない確率を1行に出力せよ。答えには10^{−6}を超える絶対誤差があってはならない。

入力例1

1
1 1
3 0 1 1
1 1

出力例1

0.0

高坂さんが南さんのカード1を引き、高坂さんと南さんは手札が空になる。
園田さんはどうしても勝つことはできない。

入力例2

1
2 1 1
1 1
2 0 1

出力例2

0.5

はじめの高坂さんのターンは、高坂さんの手札が既に空なので何もしない。次の園田さんのターンでは、園田さんは南さんの手札のうちそれぞれ0.5の確率でカード1かジョーカーを引く。カード1を引いたとき、園田さんの手札は空となり勝利する。一方ジョーカーを引いたときは、次の南さんのターンで、南さんは確実にカード1を引くので園田さんが負けとなる。

入力例3

2
3 0 1 2
3 1 2 2
3 1 1 2

出力例3

0.5

入力例4

2
2 0 1
6 2 2 2 1 1 1
1 2

出力例4

0.6666666667

Solution in Kotlin (judge verdict: Time Limit Exceeded)

fun main(args:Array<String>):Unit{
    readLine()!!
    val cards = Array(3){readLine()!!.split(' ').map(String::toInt).toIntArray().let{l ->
        (1 until l.size).map{
            l[it]
        }.groupBy { it }.filterValues { value -> value.size % 2 == 1 }.mapValues{1}
    }}
    val gameState = GameState(
            PokerFacePlayer(cards[0].size, cards[0].containsKey(0)),
            WeekPlayer(cards[1].size, cards[1].containsKey(0)),
            PokerFacePlayer(cards[2].size, cards[2].containsKey(0)))
    val memo= Array(101){Array(101){Array(101){Array(3){Rational(-1)}}}}
    println(f(gameState, memo).toDouble())
}
fun f(gameState: GameState, memo:kotlin.Array<kotlin.Array<kotlin.Array<kotlin.Array<Rational>>>>):Rational{
    if (gameState.isSonodaLose) return Rational(0)
    if (gameState.isSonodaWon) return Rational(1)
    if (memo[gameState.kosaka.cardNum][gameState.sonoda.cardNum][gameState.minami.cardNum][gameState.playerHasJoker.toInt] < 0){
        val next = gameState.next().flatMap{ sonoda ->
            val gameSonoda = sonoda.first
            val probSonoda = sonoda.second
                    gameSonoda.next().flatMap{ minami ->
                        val gameMinami = minami.first
                        val probMinami = minami.second
                                gameMinami.next().map{ kosaka ->
                                    val gameKosaka = kosaka.first
                                    val probKosaka = kosaka.second
                                            Pair(gameKosaka, probSonoda * probMinami * probKosaka)
                                        }
                            }
                }
        val same = next.filter{g -> g.first == gameState}.map{p -> p.second}.fold(Rational(1), Rational::plus)
        val diff = next.filter{g -> g.first != gameState}.map{g -> f(g.first, memo) * g.second}.fold(Rational(0), Rational::plus)
        memo[gameState.kosaka.cardNum][gameState.sonoda.cardNum][gameState.minami.cardNum][gameState.playerHasJoker.toInt] = diff / same
    }
    return memo[gameState.kosaka.cardNum][gameState.sonoda.cardNum][gameState.minami.cardNum][gameState.playerHasJoker.toInt]
}
abstract class Player(val cardNum:Int, val hasJoker:Boolean){
    abstract fun draw(drawer:Player, theOther:Player):Collection<Pair<DrawType, Rational>>
    abstract fun isWin():Boolean
    abstract fun addCard(draw:DrawType):Player
    abstract fun subCard(draw:DrawType):Player
    abstract fun numberCard():Int
}
class PokerFacePlayer(cardNum: Int, hasJoker: Boolean):Player(cardNum, hasJoker){
    override fun equals(other: Any?): Boolean {
        return when(other){
            is PokerFacePlayer -> cardNum == other.cardNum && hasJoker == other.hasJoker
            else -> false
        }
    }
    override fun isWin(): Boolean = cardNum == 0

    override fun addCard(draw: DrawType): Player = when(draw){
        DrawType.Joker -> PokerFacePlayer(cardNum + 1, true)
        DrawType.MakePair -> PokerFacePlayer(cardNum - 1, hasJoker)
        DrawType.NotMakePair -> PokerFacePlayer(cardNum + 1, hasJoker)
        DrawType.NoCard -> this
    }

    override fun subCard(draw: DrawType): Player = when(draw){
        DrawType.Joker -> PokerFacePlayer(cardNum - 1, false)
        DrawType.NoCard -> this
        else -> PokerFacePlayer(cardNum - 1, hasJoker)
    }

    override fun numberCard(): Int = cardNum - if (hasJoker) 1 else 0

    override fun draw(drawer: Player, theOther: Player): Collection<Pair<DrawType, Rational>> {
        if (cardNum == 0) return listOf(Pair(DrawType.NoCard, Rational(1)))
        val all = (cardNum + drawer.cardNum + theOther.cardNum) / 2
        return listOf(
                Pair(DrawType.Joker, Rational(if (hasJoker) 1 else 0, cardNum)),
                Pair(DrawType.MakePair, Rational(all - theOther.numberCard(), cardNum)),
                Pair(DrawType.NotMakePair, Rational(numberCard() + theOther.numberCard() - all, cardNum))
                )
    }

}
class WeekPlayer(cardNum:Int, hasJoker:Boolean):Player(cardNum, hasJoker){
    override fun equals(other: Any?): Boolean {
        return when(other){
            is WeekPlayer -> cardNum == other.cardNum && hasJoker == other.hasJoker
            else -> false
        }
    }
    override fun isWin(): Boolean = cardNum == 0

    override fun addCard(draw: DrawType): Player = when(draw){
        DrawType.Joker -> WeekPlayer(cardNum + 1, true)
        DrawType.MakePair -> WeekPlayer(cardNum - 1, hasJoker)
        DrawType.NotMakePair -> WeekPlayer(cardNum + 1, hasJoker)
        DrawType.NoCard -> this
    }

    override fun subCard(draw: DrawType): Player = when(draw){
        DrawType.Joker -> WeekPlayer(cardNum - 1, false)
        DrawType.NoCard -> this
        else -> WeekPlayer(cardNum - 1, hasJoker)
    }

    override fun numberCard(): Int = cardNum - if (hasJoker) 1 else 0

    override fun draw(drawer: Player, theOther: Player): Collection<Pair<DrawType, Rational>> {
        val all = (cardNum + drawer.cardNum + theOther.cardNum) / 2
        return when{
            all - theOther.numberCard() > 0 -> listOf(
                    Pair(DrawType.MakePair, Rational(1))
            )
            numberCard() > 0 -> listOf(
                Pair(DrawType.NotMakePair, Rational(1))
                )
            hasJoker -> listOf(
                    Pair(DrawType.Joker, Rational(1))
            )
            else -> listOf(
                    Pair(DrawType.NoCard, Rational(1))
            )
        }
    }
}
data class GameState(val kosaka:Player, val sonoda:Player, val minami:Player, val turn:PlayerName = PlayerName.Kosaka){
    override fun equals(other: Any?): Boolean {
        return when(other){
            is GameState -> kosaka == other.kosaka && sonoda == other.sonoda && minami == other.minami && turn == other.turn
            else -> false
        }
    }
    val playerHasJoker:PlayerName
        get() = when{
            kosaka.hasJoker -> PlayerName.Kosaka
            sonoda.hasJoker -> PlayerName.Sonoda
            else -> PlayerName.Minami
        }
    val isSonodaWon:Boolean
        get() = sonoda.isWin()
    val isSonodaLose:Boolean
        get() = kosaka.isWin() && minami.isWin()
    fun next():Collection<Pair<GameState, Rational>>{
        if (isSonodaWon || isSonodaLose) return listOf(Pair(this.copy(turn = when(turn){
            PlayerName.Kosaka -> PlayerName.Sonoda
            PlayerName.Sonoda -> PlayerName.Minami
            PlayerName.Minami -> PlayerName.Kosaka
        }), Rational(1)))
        return when(turn){
            PlayerName.Kosaka -> when{
                kosaka.isWin() -> listOf(Pair(this.copy(turn = PlayerName.Sonoda), Rational(1)))
                minami.isWin() -> sonoda.draw(kosaka, minami).map{p->
                    Pair(GameState(kosaka.addCard(p.first), sonoda.subCard(p.first), minami, PlayerName.Sonoda), p.second)
                }
                else -> minami.draw(kosaka,sonoda).map{p ->
                    Pair(GameState(kosaka.addCard(p.first), sonoda, minami.subCard(p.first), PlayerName.Sonoda), p.second)
                }
            }
            PlayerName.Sonoda -> when{
                sonoda.isWin() -> listOf(Pair(this.copy(turn = PlayerName.Minami), Rational(1)))
                kosaka.isWin() -> minami.draw(sonoda, kosaka).map{p ->
                    Pair(GameState(kosaka, sonoda.addCard(p.first), minami.subCard(p.first), PlayerName.Minami), p.second)
                }
                else -> kosaka.draw(sonoda, minami).map{p ->
                    Pair(GameState(kosaka.subCard(p.first), sonoda.addCard(p.first), minami, PlayerName.Minami), p.second)
                }
            }
            PlayerName.Minami -> when{
                minami.isWin() -> listOf(Pair(this.copy(turn = PlayerName.Kosaka), Rational(1)))
                sonoda.isWin() -> kosaka.draw(minami, sonoda).map{p ->
                    Pair(GameState(kosaka.subCard(p.first), sonoda, minami.addCard(p.first), PlayerName.Kosaka), p.second)
                }
                else -> sonoda.draw(minami, kosaka).map{p ->
                    Pair(GameState(kosaka, sonoda.subCard(p.first), minami.addCard(p.first), PlayerName.Kosaka), p.second)
                }
            }
        }
    }
}
enum class PlayerName(val toInt:Int){
    Kosaka(0), Sonoda(1), Minami(2)
}
enum class DrawType{
    MakePair, NotMakePair, Joker, NoCard
}
class Rational(num:Long, den:Long):Comparable<Rational>{
    override operator fun compareTo(other: Rational): Int {
        return (this - other).compareTo(0)
    }
    operator fun compareTo(other:Int):Int{
        return numerator.compareTo(denominator * other)
    }

    val denominator:Long
    val numerator:Long
    init{
        val g = gcd(abs(num), abs(den))
        denominator = abs(den) / g
        numerator = sign(num) * sign(den) * abs(num) / g
    }
    constructor(num:Long):this(num, 1)
    constructor(num:Int, den:Int):this(num.toLong(), den.toLong())

    companion object {
        private tailrec fun gcd(a:Long, b:Long):Long{
            return when(a % b){
                0L -> b
                else -> gcd(b, a % b)
            }
        }
        private fun sign(a:Long):Long{
            return when{
                a >= 0 -> 1
                else -> -1
            }
        }
        private fun abs(a:Long):Long{
            return a * sign(a)
        }


    }
}
fun Rational.toDouble():Double{
    return numerator.toDouble() / denominator
}
operator fun Rational.plus(other:Rational):Rational{
    return Rational(numerator * other.denominator + denominator * other.numerator, denominator * other.denominator)
}
operator fun Rational.plus(other:Int):Rational{
    return Rational(numerator + other * denominator, denominator)
}
operator fun Rational.plus(other:Long):Rational{
    return Rational(numerator + other * denominator, denominator)
}
operator fun Rational.minus(other:Rational):Rational{
    return Rational(numerator * other.denominator - other.numerator * denominator, denominator * other.denominator)
}
operator fun Rational.minus(other:Int):Rational{
    return Rational(numerator - other * denominator, denominator)
}
operator fun Rational.minus(other:Long):Rational{
    return Rational(numerator - other * denominator, denominator)
}
operator fun Rational.times(other:Rational):Rational{
    return Rational(numerator * other.numerator, denominator * other.denominator)
}
operator fun Rational.times(other:Int):Rational{
    return Rational(numerator * other, denominator)
}
operator fun Rational.times(other:Long):Rational{
    return Rational(numerator * other, denominator)
}
operator fun Rational.div(other:Rational):Rational{
    return Rational(numerator * other.denominator, denominator * other.numerator)
}
operator fun Rational.div(other:Int):Rational{
    return Rational(numerator, denominator * other)
}
operator fun Rational.div(other:Long):Rational{
    return Rational(numerator, denominator * other)
}
operator fun Int.plus(other:Rational):Rational{
    return Rational(this * other.denominator + other.numerator, other.denominator)
}
operator fun Long.plus(other:Rational):Rational{
    return Rational(this * other.denominator + other.numerator, other.denominator)
}
operator fun Int.minus(other:Rational):Rational{
    return Rational(this * other.denominator - other.numerator, other.denominator)
}
operator fun Long.minus(other:Rational):Rational{
    return Rational(this * other.denominator - other.numerator, other.denominator)
}
operator fun Int.times(other:Rational):Rational{
    return other * this
}
operator fun Long.times(other:Rational):Rational{
    return other * this
}
operator fun Int.div(other:Rational):Rational{
    return Rational(this * other.denominator, other.numerator)
}
operator fun Long.div(other:Rational):Rational{
    return Rational(this * other.denominator, other.numerator)
}