絶滅

どうでもいい

AtCoder Beginner Contest 075

f:id:my316g:20171014234239p:plain

時間ギリギリ 95 分弱でなんとか 4 問全部 AC できた.まあまあうれしい

f:id:my316g:20171014234246p:plain

レートは 200 ちょい上がって名前が緑色になった.

1200 まではビギナーで頑張ろうかなと思う(レギュラーで 1 完とかだと悲しいので…)




A - One out of Three

ある整数 n に対して n XOR n == 0 となるので, 配列に 2 つペアの組複数と 1 つの仲間外れがあるときは全要素の XOR をとると仲間外れがでてくる.

この問題なら A XOR B XOR C を出力しておわり

int problemA()
{
    int A, B, C;
    cin >> A >> B >> C;
 
    cout << (A ^ B ^ C) << endl;
 
    return 0;
}




B - Minesweeper

いつもの 8 方向ループだなと思ったけど脳のクロックが遅いので書くのに 10 分くらいかかった

const int dx[] = { 1, 1, 0, -1, -1, -1, 0, 1 };
const int dy[] = { 0, -1, -1, -1, 0, 1, 1, 1 };
 
int H, W;
vector<string> S;
 
void mine(int x, int y)
{
    if (S[y][x] == '#') return;
 
    int count = 0;
    for (int d = 0; d < 8; d++) {
        int nx = x + dx[d];
        int ny = y + dy[d];
 
        if (nx < 0 || W <= nx || ny < 0 || H <= ny || S[ny][nx] != '#') continue;
 
        count++;
    }
    
    S[y][x] = (char)('0' + count);
}
 
int problemB()
{
    cin >> H >> W;
    
    string tmp;
    for (int i = 0; i < H; i++) {
        cin >> tmp;
        S.push_back(tmp);
    }
 
    for (int y = 0; y < H; y++) {
        for (int x = 0; x < W; x++) {
            mine(x, y);
        }
    }
 
    for (int i = 0; i < H; i++) cout << S[i] << endl;
 
    return 0;
}




C - Bridge

なんとなく Union Find とか使うんだろうなぁと思ったけど慣れてなかったので BFS でなんとかした

グラフの問題まあまあ苦手

typedef pair<int, int> edge;
vector<edge> edges;
 
int problemC()
{
    int N, M, ans = 0;
    cin >> N >> M;
 
    int v, w;
    for (int i = 0; i < M; i++) {
        cin >> v >> w;
        edges.push_back(edge(v, w));
    }
 
    // i : off にする辺
    for (int i = 0; i < M; i++) {
 
        vector<vector<int> > li(N + 1);
        // 辺 i を除いて隣接リストを作る
        for (int j = 0; j < M; j++) {
            if (j == i) continue;
            edge e = edges[j];
            li[e.first].push_back(e.second);
            li[e.second].push_back(e.first);
        }
 
        queue<int> qu;
        set<int> st;
 
        qu.push(1);
 
        // 頂点 1 とつながっている頂点の個数を数える
        while (!qu.empty()) {
            int v = qu.front();
            qu.pop();
            st.insert(v);
 
            for (int k = 0; k < li[v].size(); k++) {
                if (st.find(li[v][k]) == st.end()) qu.push(li[v][k]);
            }
        }
 
        // N でなければ連結成分が複数ある
        if (st.size() != N) ans++;
    }
 
    cout << ans << endl;
 
    return 0;
}




D - Axis-Parallel Rectangle

50Ci (K <= i <= N) について一個一個調べてたら無理だよな~ということで

  • x 座標で点 P[i] をソート
  • 区間 [P[i].x, P[j].x] に点が K 個以上含まれるような (i, j) に対して
    • 横の長さ w = P[j].x - P[i].x とおく
    • P[i], P[i + 1], ..., P[j] の y 座標を Y[] に格納してソート
    • 区間 [Y[ii], Y[jj]] に点が K 個以上含まれるような (ii, jj) に対して
      • 縦の長さ h = Y[jj] - Y[ii] とおく
      • 面積 w * h で最小値を更新

この方針でいったら無事 AC した.O(N4) かな?

typedef long long lint
#define all(x) (x).begin(), (x).end()
#define INF ((lint)4000000000000000010)

typedef pair<lint, lint> pii;
 
int problemD()
{
    lint N, K;
    lint ans = INF;
    cin >> N >> K;
    vector<pii> ps;
 
    lint x, y;
    for (lint i = 0; i < N; i++) {
        cin >> x >> y;
        ps.push_back(pii(x, y));
    }
 
    sort(all(ps));
 
    // x : 間に K 個以上の点を含む 2 点を選択 [i, j]
    for (lint i = 0; i <= ps.size() - K; i++) {
        for (lint j = i + K - 1; j < ps.size(); j++) {
 
            // 横幅
            lint width = ps[j].first - ps[i].first;
            //cout << "width = " << width << endl;
 
            vector<lint> ys;
            for (int k = i; k <= j; k++) {
                ys.push_back(ps[k].second);
            }
 
            sort(all(ys));
 
            // y : 間に K 個以上の点を含む 2 点を選択
            for (lint ii = 0; ii <= ys.size() - K; ii++) {
                for (lint jj = ii + K - 1; jj < ys.size(); jj++) {
 
                    lint height = ys[jj] - ys[ii];
                    lint area = width * height;
 
                    if (ans > area) ans = area;
 
                }
            }
 
        }
    }
 
    cout << ans << endl;
 
    return 0;
}

最後焦ってたのでコードが雑