ICPC2016 国内予選

2016/06/24 (Fri) ICPC

ACM-ICPC アジア地区つくば大会 2016 (57577) 国内予選に参加した記録です.
チームは私 tubo28 (M1) + femto 君 (M1) + F 君 (B4) です. 時間はファイルの lastmod なので順位表とは若干ずれています.

3日前

会場になる計算機室のコンピュータを触ってみる.
以前から聞いてはいたけど Cent OS + HHKB Lite JP 配列で クソ 不慣れすぎるのでパソコンとプリンタの持ち込みを決意する.
チームメイトは二人共 Visual Studio のプロなので Windows ノートを使うことにする.

当日

A 問題

F 君が担当する.
しばらくして AC.
16:35

B 問題

femto 君が担当する.
しばらくして AC.
16:48

C 問題

僕が解く.
最初慌てていて問題文が頭に入ってこない.落ち着いて読めばエラトステネスなのに 20 分もかかってしまった. 入力の順番が僕の感覚とは逆で混乱した (主観).
17:08

D 問題

femto 君が B を書いている間にだいたい解法は見えていたので二人に説明して確認する. 最初に区間 DP で全部とれる区間を求め,次にそれらが被らないように前からなるべく長く選ぶ DP をするやつ. TDPC の iwiwi みたいにすると解ける.
僕は区間 DP を必ずバグらせるので femto くんに書いてもらうがそれでもバグる. 迷走しつつも区間 DP は完成する.
あとはナップサックみたいな DP をするだけなんだけどそれもバグらせてしまう. 今思えば,区間 DP を閉区間で,次の DP を左閉右開区間でやったことが原因だと思う.
ふたつ目の DP は 蟻本初級編以下なのに詰まるのダメすぎる…
いろいろやってる内にサンプルが合って出すと AC.
18:34

E 問題

M1 が D 問題と戯れている間に F 君が F 問題を読んでくれていたので説明を聞く. deg(v) <= 2 の制約から画像はこけおどしだと気づく. しかし,その条件下ではグラフがパスかサイクルにしかならないというところまでは気づかない. さらに最終的なグラフが連結でないといけないという制約を見落とす. いろいろ考えている内に時間切れ.

F 問題以降

見ていない.

コンテスト後

なんとか通過していた (28th).
いつもの SRM と同じような黄色コーダーと青コーダーの境界みたいな位置だった .
監督の先生に E の解法を聞いて愕然とする.
なんで気が付かなかったんだ…

実装

コンテスト中に書いたプログラムです. 整理していないので汚いです.

A

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
    int n;

    while (cin >> n, n) {
        vector<int> a;
        
        for (int i = 0; i < n; i++) {
            int x;
            cin >> x;
            a.push_back(x);
        }

        sort(a.begin(), a.end());

        int ans = 1e9;
        for (int i = 0; i < n - 1; i++) {
            int d = a[i] - a[i + 1];
            d = -d;
            ans = min(ans, d);
        }

        cout << ans << endl;
    }

}

B

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;
typedef pair<int, char> P;
int n;
void solve() {
    char cs[100];
    int num[26] = { 0 };
    for (int i = 0; i < n; i++) {
        cin >> cs[i];
    }
    for (int i = 0; i < n; i++) {
        int rem = n - i - 1;
        char c = cs[i];
        num[c - 'A']++;
        vector<P > v;
        for (int j = 0; j < 26; j++) {
            v.push_back(P(num[j], 'A' + j));
        }
        sort(v.begin(), v.end());
        reverse(v.begin(), v.end());

        if (v[0].first - v[1].first > rem) {
            cout << v[0].second << " " << i + 1 << endl;
            return;
        }
    }

    cout << "TIE" << endl;
    return;
}

int main() {
    while (cin >> n, n) {
        solve();
    }
}

C

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

const int N = 7368791 + 10;
int divisible[N];

int main() {
    int n, m;
    while (cin >> m >> n && m) {
        fill(divisible, divisible + N, false);
        int cnt = 0;
        for (int j = m; cnt < n; ++j) {
            if (divisible[j]) continue;
            divisible[j] = true;
            ++cnt;
            for (int k = j + j; k < N; k += j) {
                divisible[k] = true;
            }
        }
        for (int j = m;; ++j) {
            if (divisible[j]) continue;
            cout << j << endl;
            break;
        }
    }
}

D

#include <iostream>
#include <vector>
#include <cassert>
#include <algorithm>
#include <cstring>

using namespace std;

int n;
int dp1[510][510];
vector<int> a;

bool mergeable(int i, int j) {
    return abs(a[i] - a[j]) <= 1;
}

int f(int l, int r) {
    int &res = dp1[l][r];
    if (res != -1) return res;
    bool ok = false;
    assert(r != l);
    if (l + 1 == r) {
        return res = abs(a[l] - a[r]) <= 1; // 0
    }
    if (l + 2 == r) {
        return res = false;
    }

    for (int i = l + 1; i + 1 <= r - 1; i++) {
        if (f(l, i) == 1 && f(i + 1, r) == 1) {
            ok = true;
        }
    }

    ok |= f(l + 1, r - 1) && mergeable(l, r);

    //for (int i = l + 2; i + 1 <= r - 1; i++) {
    //    if (f(l + 1, i) && f(i + 1, r - 1)) {
    //        ok = true;
    //    }
    //}

    return res = ok;
}

using pii = pair<int, int>;
vector<pii> v;

int can[510][510];
int dp2[510];

int main() {
    while (cin >> n && n) {
        a.resize(n);
        for (int i = 0; i < n; i++) {
            cin >> a[i];
        }

        memset(dp1, -1, sizeof(dp1));
        v.clear();

        f(0, n - 1);
        for (int l = 0; l <= n - 1; l++) {
            for (int r = l; r <= n - 1; ++r) {
                for (int i = l + 1; i + 1 < r; ++i) {
                    f(l, i);
                    f(i + 1, r);
                    if (dp1[l][i] == 1 && dp1[i + 1][r] == 1) {
                        v.emplace_back(l, r);
                    }
                }
            }
        }
        for (int i = 0; i < n; ++i) {
            for (int j = i + 1; j < n; ++j) {
                if (dp1[i][j] == 1) {
                    v.emplace_back(i, j);
                }
            }
        }

        sort(v.begin(), v.end());
        v.erase(unique(v.begin(), v.end()), v.end());

        memset(can, 0, sizeof can);
        for (int i = 0; i < v.size(); i++) {
            can[v[i].first][v[i].second] = true;
        }

        //for (int i = 0; i < n; i++) {
        //    for (int j = 0; j < n; j++) {
        //        if (can[i][j]) {
        //            cout << i << " " << j << endl;
        //        }
        //    }
        //}

        memset(dp2, 0, sizeof dp2);
        for (int i = 0; i <= n; i++) {
            if (i) dp2[i] = max(dp2[i - 1], dp2[i]);
            for (int j = i + 1; j <= n; ++j) {
                if (can[i][j - 1]) {
                    dp2[j] = max(dp2[j], dp2[i] + (j - i));
                }
            }
        }

        int ans = 0;
        for (int i = 0; i < 510; i++) {
            ans = max(ans, dp2[i]);
        }
        cout << ans << endl;
    }
}