BOJ 27559 - Following Directions

image.png

구현중 오타가 나서 고생했다.

$in[y][x]$ 를 자신에게 도달하는 소의 개수라고 하자.

그럼 각 쿼리마다 이 $in$ 배열을 업데이트 시켜준 후 모든 row와 column에 대해 vat 값과 in 의 개수를 곱해줘서 모두 더해준 것이 정답이고 이걸 세는건 $O(n)$에 된다.

그럼 $in$을 어떻게 업데이트 하냐가 문제의 핵심인데, $(y,x)$가 flip 되었을 때 $(y+1,x)$와 $(y,x+1)$ 의 $in$이 변한다.

이후에 $(y+1,x),(y,x+1)$ 로부터 끝까지 갈때까지 거치는 칸들에 대해서만 $in$이 변한다는 것을 증명할 수 있기 때문에 결국 업데이트도 $O(n)$으로 가능하다.

즉, $O(qn)$에 문제를 해결할 수 있다.

void solve() {
   int n;
   cin >> n;
   vs dir(n);
   vi cost_col(n + 5), cost_row(n + 5);
   for (int i = 0; i < n + 1; i++) {
      if (i < n) {
         cin >> dir[i];
         cin >> cost_row[i];
      } else {
         for (int j = 0; j < n; j++) cin >> cost_col[j];
      }
   }

   vvi in(n + 1, vi(n + 1));
   for (int y = 0; y < n; y++)
      for (int x = 0; x < n; x++) {
         in[y][x]++;
         if (dir[y][x] == 'D') in[y + 1][x] += in[y][x];
         else in[y][x + 1] += in[y][x];
      }
   ll ans = 0;
   for (int i = 0; i < n; i++) {
      ans += in[i][n] * cost_row[i];
      ans += in[n][i] * cost_col[i];
   }
   cout << ans << endl;

   int query;
   cin >> query;
   vvi vis(n + 1, vi(n + 1));
   while (query--) {
      int sy, sx;
      cin >> sy >> sx, sy--, sx--;
      dir[sy][sx] = dir[sy][sx] == 'D' ? 'R' : 'D';

      function<void(int, int)> fn = [&](int y, int x) -> void {
         in[y][x] = (y == n || x == n) ? 0 : 1;
         if (y != 0 && x != n && dir[y - 1][x] == 'D') in[y][x] += in[y - 1][x];
         if (x != 0 && y != n && dir[y][x - 1] == 'R') in[y][x] += in[y][x - 1];

         if (y == n || x == n) return;
         if (dir[y][x] == 'R') {
            fn(y, x + 1);
         } else {
            fn(y + 1, x);
         }
      };

      fn(sy + 1, sx);
      fn(sy, sx + 1);

      ans = 0;
      for (int i = 0; i < n; i++) {
         ans += in[i][n] * cost_row[i];
         ans += in[n][i] * cost_col[i];
      }
      //cout << "\n----------\n";
      //print(dir);
      //print(in);
      cout << ans << endl;
   }
}

Tags:

Categories:

Updated:

Comments