POH6「漫画版: 女子高生プログラマーの大バトル!~コボール文明の逆襲~」


概要

さあ今回もやってまいりましたPOH(Paiza Online Hackathon)。
どう見ても某ゲーム小僧っぽいポーズで笑いを誘いつつ、遺跡より蘇るスフィンクスっぽい敵を迎え撃つは美少女プログラマー3人!
プログラミングで世界を、地球を救うことはできるのか!?

……いや今回のは前回より簡単なんでマなら解けないと困りますマジで。

霧島京子編

まずはランク1 オッツダルヴァ。一部で不人気とか言ってる声もあるけどふざけるな、可愛いやろ! あっ俺は六村さんでお願いします
本来は動的計画法で解く問題らしいのだが、思いつかなかったので普通にシミュレートして実装した。説明する前にコード貼った方が早いよね?

code1.cpp
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main(){
    // 入力
    int n;
    cin >> n;
    vector<int> t(n);
    for(int i = 0; i < n; ++i){
        cin >> t[i];
    }
    int m;
    cin >> m;
    vector<int> d(m);
    for(int i = 0; i < m; ++i){
        cin >> d[i];
    }
    // 処理
    vector<string> result(m);
    for(int i = 0; i < m; ++i){
        // 出目の値が大きすぎるとゲームオーバーなので"No"
        if(d[i] >= n){
            result[i] = "No";
            continue;
        }
        // 移動をシミュレートして、ゴールに行けない場合を弾く
        vector<int> check(n, 0);
        check[0] = 1;   //最初のマスに印を付けておく
        int pos = d[i];
        while(true){
            // ゴールに着いた場合は"Yes"
            if(pos == n - 1){
                result[i] = "Yes";
                break;
            }
            // 移動先がすごろくの外なら"No"
            if(pos + t[pos] >= n){
                result[i] = "No";
                break;
            }
            if(pos + t[pos] < 0){
                result[i] = "No";
                break;
            }
            // 移動先が既に行った所なら"No"
            // (無限ループの恐れがあるので)
            if(check[pos + t[pos]] != 0){
                result[i] = "No";
                break;
            }
            // 移動を行う
            check[pos] = 1;
            pos += t[pos];
        }
    }
    // 出力
    for(int i = 0; i < m; ++i){
        cout << result[i] << "\n";
    }
}

正直、無限ループ考慮するので地味に面倒だなと思いました(小並感)

六村リオ編

ナンバー2さんの登場だ。言語別集計から察するに一番人気っぽいねこの子。ぱっと見解きやすい、というわけでもないのに何故だろう?
霧島と同じくシミュレートして解ける問題だけど、見ての通りコードはより簡単。だけど、テストケース5で躓く人が続出しているそうな。何故だろう?

code2.cpp
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main(){
    // 操作回数を入力する
    int N;
    cin >> N;
    // 各手順を実行する
    double water = 0.0, coffee = 0.0;
    for(int i = 0; i < N; ++i){
        // 手順を読み込む
        int t, s;
        cin >> t >> s;
        // 手順を処理する
        if(t == 1){
            // お湯を入れる
            water += s;
        }else if(t == 2){
            // コーヒー粉末を入れる
            coffee += s;
        }else{
            // 中身を飲む
            double water_ = water - water * s / (water + coffee);
            double coffee_ = coffee - coffee * s / (water + coffee);
            water = water_;
            coffee = coffee_;
        }
    }
    // 濃度を計算する
    cout << static_cast<int>(coffee * 100 / (water + coffee)) << endl;
}

躓いた方に伺ったところ、どうやらテストケース5には「中身を飲む」操作が入っているらしい。コードを読めば分かるように、中身を飲む場合は副作用の問題があるので、一旦更新前の水・コーヒー粉末量をコピーしてから更新するのが安全
最後は四捨五入じゃなくて整数型にキャストしているのは問題文通り。

緑川つばめ編

そして第三位。黒髪ロング、そして「なでしこ(ハッカー)」とかいうヲタ受けしそうな実装なのにも関わらず投稿数も第三位なようで……。アイエエエエ! フニンキ!? フニンキナンデ!?
コードも何気に一番簡単に済んだ。マジでランクごとに難易度も下げているのかと思ったじぇ(まあ全体的に易化しているが)。

code3.cpp
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main(){
    // 整数を入力する
    int N;
    cin >> N;
    // 報酬を計算・出力する
    cout << (N + static_cast<int>(N / 10) + (N % 10)) << endl;
}

振り返って

前回のPOHに比べて易しすぎる感がある……まあ温い方がストーリーを楽しめるからいいか、と思ってたがストーリー部分も薄いからつらたん。
POH6+は骨があるので次回で解説。