第16回日本情報オリンピック 2016/2017 予選に参加した話

結果

これと比較した感じだと380点でした.
提出ミスしてなければ幸いです.
(追記) 360点で予選通過してました.プロ各位宜しくお願いします.ちなみに5問目の1ケースにinputを投げてしまい,20点を失いました.

1問目

やるだけ.もうちょっとコンパクトなコードを書きたかった.無駄な部分が多い.

// テンプレ省略

signed main() {
  int a, b, c, d, e;
  cin >> a >> b >> c >> d >> e;

  int ans = 0;
  if (b == a) {
    print(ans);
    return 0;
  }
  if (a < 0) {
    ans += c * abs(a);
    a = 0;
  }
  if (a == b) {
    print(ans);
    return 0;
  }
  if (a == 0) {
    ans += d;
  }
  print(ans + (b - a) * e);

  return 0;
}

2問目

これもやるだけ.b は使わなくていい.

signed main() {
  int n, m;
  cin >> n >> m;
  int ans = 0;
  vi a(m);
  REP(i, m) {
    int b;
    cin >> a[i] >> b;
  }
  sort(ALL(a));
  reverse(ALL(a));
  REP(i, m - 1) {
    if (a[i] < n) {
      ans += (n - a[i]);
    }
  }
  print(ans);

  return 0;
}

3問目

D という長さになればいいのである地点から東西南北4方向を見て# でなければそこからdfsをして,深さがD になったら答えに1加える.方向を引数でもってやればいい.最終的に出た数は被りがあるので2で割ってやる.別にfor でやっても良かった.
例年の3問目よりかなり簡単なのでは.多分ここらへんまでで30~40分.

int n, m, d;
char s[128][128];
int ans;

void dfs(int y, int x, int dep, int ddy, int ddx) {
  if (dep == d) {
    ans++;
    return;
  }
  int ny = y + ddy, nx = x + ddx;
  if (!inside(ny, nx, n, m)) return;
  if (s[ny][nx] == '#') return;
  dfs(ny, nx, dep + 1, ddy, ddx);
}

signed main() {
  cin >> n >> m >> d;
  REP(i, n) cin >> s[i];

  REP(i, n) REP(j, m) {
    if (s[i][j] != '#') {
      REP(k, 4) {
        int ny = i + dy[k], nx = j + dx[k];
        if (!inside(ny, nx, n, m)) continue;
        if (s[ny][nx] == '#') continue;
        dfs(i, j, 1, dy[k], dx[k]);
      }
    }
  }
  print(ans / 2);

  return 0;
}

4問目

テストケース1~3まで通しました.bitDPらしいですね.わかりません.
脳を完全に停止してnext_permutation() をし,順列を全列挙した.順列は最大でm! 種類あるのでm が大きい値だと計算量がまずい.このコードだとO(n * m!)になりますかねえ.ひどいなこれ. 順列と元のぬいぐるみと比較して,違う種類だったらカウント.そしてmin をとる.1時間ぐらいずっと回してた.

signed main() {
  int n, m;
  cin >> n >> m;
  vi a(n), b(m), cnt(n + 1);
  REP(i, m) b[i] = i + 1;
  REP(i, n) {
    cin >> a[i];
    cnt[a[i]]++;
  }
  int res = INF;
  do {
    int c = 0;
    int idx = 0;
    REP(i, m) REP(j, cnt[b[i]]) {
        if (a[idx++] != b[i]) c++;
      }
    }
    chmin(res, c);
  } while (next_permutation(ALL(b)));
  print(res);
  
  return 0;
}

問題5

解法が思いつかず,適当にdfsしたら1ケース目は通った.残りはなんかセグフォが起きたので諦めた.

int h, w;
vvi a;
int sum = 0;
bool vis[1000][1000];

void dfs(int y, int x, bool fi = false) {
  bool flg = false;
  REP(i, 4) {
    int ny = y + dy[i], nx = x + dx[i];
    if (!inside(ny, nx, h, w)) continue;
    if (a[y][x] > a[ny][nx]) {
      flg = true;
      dfs(ny, nx);
    }
  }
  if (!flg && !fi && !vis[y][x]) {
    sum++;
    vis[y][x] = true;
  }
}

signed main() {
  cin >> h >> w;
  a = vvi(h, vi(w));
  REP(i, h) REP(j, w) cin >> a[i][j];
  int res = 0;
  REP(i, h) REP(j, w) {
    memset(vis, 0, sizeof(vis));
    sum = 0;
    dfs(i, j);
    if (sum > 1) res++;
  }
  print(res);

  return 0;
}

問題6

拡張dijkstraらしいですね.
「いい感じにするdijkstraやろ!w」
と思ったけど,ぼくはスーパー適当なdijkstraを書いてsampleが通らないけど取り敢えず出しました.全ケース落ちました.コードは載せません. まぁでも,去年はdijkstraという言葉すら知らかったので成長はしたのかなという感じです.

感想

つらいです.3問目までめっちゃ簡単で「いけるやろ~」と調子に乗ったら,難易度が跳ね上がりました.明らかに精進不足です. もし予選通ってたら,本選までにDPとか克服していきたいです.

あと3問目まで答えを格納する変数名がans なのに4問目からres なのウケますね.