POH6 漫画版: 女子高生プログラマーの大バトル!〜コボール文明の逆襲〜 六村リオ


六村リオ / 霧島京子 / 緑川つばめ / 島根ルミ / 島根ルミ149 / 島根ルミ121 / 共通解

https://paiza.jp/poh/joshibato
色々混ざりすぎだろ。

コーヒーの濃さを求める問題

<?php
    // インプット
    $f = file('php://stdin', FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES);
    // 1行目は不要
    unset($f[0]);

    // 初期化
    $oyu = $coffee = 0;

    // くるくる
    foreach($f as $v){
        $v=explode(' ', $v, 2);
        if($v[0]==="1"){ // お湯
            $oyu += $v[1];
        }elseif($v[0]==="2"){ // コーヒー
            $coffee += $v[1];
        }else{ // 飲んだ
            $oyu -= ($v[1]*$oyu) / ($oyu+$coffee);
            $coffee -= ($v[1]*$coffee) / ($oyu+$coffee);
        }
    }

    // 濃度
    echo intval(100*$coffee/($oyu+$coffee));

https://paiza.jp/poh/joshibato/rio/result/a0b8757d
どう見ても合ってるはずなんだが、何故かテストケース5が誤答になる。
なんで??
誤差か?誤差のせいなのか?

<?php
    // インプット
    $f = file('php://stdin', FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES);
    // 1行目は不要
    unset($f[0]);

    // 初期化
    $oyu = $cof = "0";
    bcscale(64);

    // くるくる
    foreach($f as $v){
        $v=explode(' ', $v, 2);
        if(!$v[1]){continue;}

        if($v[0]==="1"){ // お湯
            $oyu = bcadd($oyu, $v[1]);
        }elseif($v[0]==="2"){ // コーヒー
            $cof = bcadd($cof, $v[1]);
        }else{ // 飲んだ
            $oyu = bcsub($oyu, bcdiv(bcmul($v[1], $oyu), bcadd($oyu, $cof)));
            $cof = bcsub($cof, bcdiv(bcmul($v[1], $cof), bcadd($oyu, $cof)));
        }
    }

    // 濃度
    echo (int)bcdiv(bcmul($cof, "100"), bcadd($oyu, $cof));

https://paiza.jp/poh/joshibato/rio/result/540f6b4c
やはり駄目だった。
どうも誤差のせいではないようだ。
なおGMP関数は使えなかった。

と、ここまで書いたところでようやく大ポカに気付く。

<?php
    // インプット
    $f = file('php://stdin', FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES);
    // 1行目は不要
    unset($f[0]);

    // 初期化
    $oyu = $coffee = 0;

    // くるくる
    foreach($f as $v){
        $v=explode(' ', $v, 2);
        if($v[0]==="1"){ // お湯
            $oyu += $v[1];
        }elseif($v[0]==="2"){ // コーヒー
            $coffee += $v[1];
        }else{ // 飲んだ
            $tmp = $oyu - ($v[1]*$oyu) / ($oyu+$coffee);
            $coffee -= ($v[1]*$coffee) / ($oyu+$coffee);
            $oyu = $tmp;
        }
    }

    // 濃度
    echo intval(100*$coffee/($oyu+$coffee));

https://paiza.jp/poh/joshibato/rio/result/80a1508f
飲んだ時に$oyuを上書きしてしまったため、$coffeeの計算がおかしくなっていただけだった。
これは恥ずかしい。

PHPでは複数の計算を副作用なしに同時に行う術はないはずなので、一時変数を使って回避。
list($a, $b) = ($a+$b, $a-$b);
UPDATE table SET 主キー = CASE WHEN 主キー=1 THEN 2 WHEN 主キー=2 THEN 1 ELSE 主キー END;
みたいな芸当ができないのが悲しいところ。

これでようやく100点が取れました。

なお気付いた経緯は、入力サンプルとして
1 10
2 10
3 10
を突っ込んでみたから。