AtCoder Beginner Contest 274

結果

A - Batting Average:AC(3:10)
B - Line Sensor:AC(10:59)
C - Ameba:AC(37:25)
D - Robot Arms 2:WA

A - Batting Average

整数$${A,B}$$が与えられ、$${\frac{B}{A}}$$を小数第4位で四捨五入した値を出力する問題

自分の回答

int main(){
  double A, B;
  cin >> A >> B;
  printf("%4.3lf\n", B/A);
}

そのまま

公式解説

同じため省略

B - Line Sensor

縦$${H}$$、横$${W}$$マスのグリッドがあり、各マスに「.」か「#」がある
各列に#がいくつあるかを求める問題

自分の回答

int main(){
  int H, W;
  cin >> H >> W;
  vector<int> count(W, 0);
  for(int i = 0; i < H; i++){
    for(int j = 0; j < W; j++){
      char C;
      cin >> C;
      if(C == '#'){
        count[j]++;
      }
    }
  }
  for(int i = 0; i < W; i++){
    printf("%d", count[i]);
    if(i == W - 1){
      printf("\n");
    }
    else{
      printf(" ");
    }
  }
}

そのまま

公式解説

同じため省略

C - Ameba

最初アメーバが1匹存在し、それに1という番号をつけた
$${A_{i}}$$のアメーバが分裂して消滅し、生まれた2匹のアメーバにそれぞれ$${2i、2i+1}$$という番号をつけたという記録が$${N}$$個ある
このとき$${2i、2i+1}$$に対する$${A_{i}}$$を親という
1から$${2N+1}$$番まで何代遡れば1のアメーバとなるかを求める問題

自分の回答

int main(){
  int N;
  cin >> N;
  vector<int> gen(N * 2 + 2);
  gen[1] = 0;
  printf("0\n");
 
  for(int i = 1; i <= N; i++){
    int A;
    cin >> A;
    gen[i * 2] = gen[A] + 1;
    gen[i * 2 + 1] = gen[A] + 1;
    printf("%d\n%d\n", gen[i * 2], gen[i * 2 + 1]);
  }
}

1から順番に分裂先へ親の世代+1を入れていく
あと1回出てきた番号はそれで終わりだから出力も組み込んだ
直感的に書きやすいようにアメーバの番号と配列の番号を一致させた

公式解説

同じため省略

D - Robot Arms 2

長さ$${N}$$の正整数列$${(A_{1},A_{2},…A_{N})}$$と整数$${x,y}$$が与えられ、座標平面上において点$${p_{1}=(0,0)}$$から$${p_{2}=(A_{1},0)}$$へ移動し、その後は左右どちらかへ90度曲がり$${A_{i}}$$だけ移動した点を$${p_{i+1}}$$とする操作を$${N}$$回繰り返し、最終的に$${(x,y)}$$へたどり着けるかを判定する問題

自分の回答

int N, gx, gy;
 
void DFS(int nowx, int nowy, char Bmove, int count, vector<int> &dis){
  if(count == N){
    if(nowx == gx && nowy == gy){
      printf("Yes\n");
      exit(0);
    }
    else{
      return;
    }
  }
 
  int next = count + 1;
  if(Bmove == 'X'){
    DFS(nowx, nowy + dis[count], 'Y', next, dis);
    DFS(nowx, nowy - dis[count], 'Y', next, dis);
  }
  if(Bmove == 'Y'){
    DFS(nowx + dis[count], nowy, 'X', next, dis);
    DFS(nowx - dis[count], nowy, 'X', next, dis);
  }
}
 
int main(){
  cin >> N >> gx >> gy;
  vector<int> dis(N);
  for(int i = 0; i < N; i++){
    cin >> dis[i];
  }
 
  DFS(dis[0], 0, 'X', 1, dis);

  printf("No\n");
}

深さ優先探索で解けそうだから書いてみた
$${N}$$が最大$${10^3}$$で分岐が2だから時間大丈夫かなと思ったけどダメだった

コード自体はちゃんと書けたから多分根本的なやり方が違う

公式解説

constexpr int M = 10000;
int N, x, y, A[1010], buf1[2 * M + 1], buf2[2 * M + 1], buf3[2 * M + 1];

int main() {
  cin >> N >> x >> y;
  for (int i = 0; i < N; i++) cin >> A[i];
  int *dp1 = buf1 + M, *dp2 = buf2 + M, *dp3 = buf3 + M;
  dp1[A[0]] = dp2[0] = true;
  for (int i = 1; i < N; i++) {
    for (int j = -M; j <= M; j++) dp3[j] = 0;
    int a = A[i];
    if (i % 2 == 0) {
      for (int j = -M; j <= M - a; j++) {
        dp3[j + a] |= dp1[j], dp3[j] |= dp1[j + a];
      }
      swap(dp1, dp3);
    } else {
      for (int j = -M; j <= M - a; j++) {
        dp3[j + a] |= dp2[j], dp3[j] |= dp2[j + a];
      }
      swap(dp2, dp3);
    }
  }
  cout << (dp1[x] and dp2[y] ? "Yes" : "No") << endl;
}

https://atcoder.jp/contests/abc274/editorial/5079より

まず$${i}$$が奇数の時$${x}$$軸方向に動き、偶数の時$${y}$$軸方向に動くからそれぞれ分けて考えられるのか
で、dp1が$${x}$$軸、dp2が$${y}$$軸でどの位置なら行くことができるのかdp3が1,2から$${A_{i}}$$で移動できる場所の一時保管用
全ての位置に対して終わったら3の結果を元のに移して次の$${i}$$に行くのを$${i=1}$$から繰り返していく動的計画法

なるほど、その発想は無かった

この記事が気に入ったらサポートをしてみませんか?