【AtCoder】ABC 461 D - Count Subgrid Sum = K

D - Count Subgrid Sum = Katcoder.jp favicon

実行時間制限: 4 sec / メモリ制限: 1024 MiB / Difficulty: 914 / NoviSteps: 1Q / 配点: 425

問題概要

H×WH \times W のグリッドがあり、各マスには 00 または 11 の整数が書き込まれていて、書き込まれた整数の情報は HH 個の長さ WW の文字列 S1,S2,,SHS_1,S_2,\dots,S_H として与えられる。

書き込まれた整数の総和が KK となる長方形領域がいくつあるか求めよ。

制約

  • H,WH,W11 以上 500500 以下の整数
  • KK00 以上 HWHW 以下の整数
  • SiS_i0, 1からなる長さ WW の文字列

考察

いきなり長方形領域の四隅を考えるのは大変なので、まずは上下を固定して考えよう。

上下を top\mathrm{top} 行目と bottom\mathrm{bottom} 行目に固定 (1topbottomH)(1 \leq \mathrm{top} \leq \mathrm{bottom} \leq H) し、 jj 列目の値の累積和col_sumj\mathrm{col\_sum}_j とする。

すると、求める長方形領域の条件は、 j=lrcol_sumj=K\displaystyle \sum_{j=l}^{r} \mathrm{col\_sum}_j = K となるような区間 [l,r][l, r] の個数を求めることに帰着される。


ここで、ある配列 AA と整数 xx に対して、 i=lrAix\displaystyle \sum_{i=l}^{r} A_i \geq x が成り立つような (l,r)(l, r) の組の個数を数える関数を count(x)\mathrm{count}(x) とすると、求める答えは count(K)count(K+1)\mathrm{count}(K) - \mathrm{count}(K + 1) となる。

グリッド上の整数は非負であるため、区間を広げるとその区間内の総和は広義単調増加となる。 よって、 count(x)\mathrm{count}(x) は尺取り法の要領で計算量 O(W)O(W) で求めることができる。

なお、 K=0K = 0 の場合は col_sum\mathrm{col\_sum} の全ての連続部分列の個数になるので、 count(0)=W(W+1)2\mathrm{count}(0) = \dfrac{W(W + 1)}{2} となる。


また、上下の選び方は二重ループを回せば O(H2)O(H^2) で全探索できるので、全体の計算量は O(H2W)O(H^2 W) となり、これは本問の制約下で十分高速である。

実装例

CPP
1.#include <bits/stdc++.h>
2.using namespace std;
3.
4.#define rep(i, start, end) for (auto i = (start); (i) < (end); (i)++)
5.
6.using ll = long long;
7.
8.// ======================================== //
9.
10.int main()
11.{
12. int H, W, K;
13. cin >> H >> W >> K;
14. vector<string> S(H);
15. rep(i, 0, H) cin >> S[i];
16.
17. vector<vector<int>> grid(H, vector<int>(W, -1));
18. rep(i, 0, H) rep(j, 0, W) grid[i][j] = S[i][j] - '0';
19.
20. ll ans = 0;
21. rep(top, 0, H) {
22. vector<int> col_sum(W, 0);
23. rep(bottom, top, H) {
24. rep(j, 0, W) col_sum[j] += grid[bottom][j];
25.
26. auto count = [&](int x) -> ll {
27. if (x == 0) return W * (W + 1) / 2;
28.
29. ll res = 0;
30. int r = 0, sum = 0;
31. rep(l, 0, W) {
32. while (r < W && sum < x) {
33. sum += col_sum[r];
34. r++;
35. }
36.
37. if (sum >= x) res += W - r + 1;
38. sum -= col_sum[l];
39. }
40.
41. return res;
42. };
43.
44. ans += count(K) - count(K + 1);
45. }
46. }
47.
48.
49. cout << ans << endl;
50.
51. return 0;
52.}
Submission #76511342 - AtCoder Beginner Contest 461atcoder.jp favicon

実装時間: 45分

コメント

ちなみに、なんとこの問題は単純な二次元累積和を用いた O(H2W2)O(H^2 W^2) の解法が通ってしまうらしい。

x.com favicon

だったらもっと早く解けたわ...