LoginSignup
0
0

二次元累積和 (paizaランク B 相当)

Posted at

累積和を2次元でやればいいので
こんな風に書けばいいはずだと思ってたんですが、
どうも違うようで。。。

H,W,N = map(int,input().split())
A = [list(map(int,input().split())) for _ in range(N)]
ans = [[0,0,0]] + A[:]
for i in range(1,H + 1):
    for j in range(1, W + 1):
        ans[i][j] += ans[i-1][j-1]

つまり、Ansで雛形を作ったんですが、

[[0, 0, 0], [1, 2, 3], [4, 5, 6], [7, 8, 9]]

ではなく

 [0, 1, 2, 3], [0, 4, 5, 6], [0, 7, 8, 9]]

こうしないとだめだった。
じゃあどうするか。
結局は4つ分の0で配列を作ってあとからA配列を入れていくという感じになる。

H, W, N = map(int, input().split())
A = [list(map(int,input().split())) for _ in range(N)]
#W*Hの配列に0を入れたものを作る(0の分だけ+1する)
ans = [[0] * (W + 1) for _ in range(H + 1)]

こうですね。
で、次にA配列をAnsに入れていくのだけど、
どうするかというと、
1行目〜H行目の配列に(つまりans[i])
最初が0で、その次にAの配列を入れるので
こうなる

for i in range(1, H + 1):
    ans[i] = [0] + A[i - 1][:]

これで一回ansを出力

 [0, 1, 2, 3], [0, 4, 5, 6], [0, 7, 8, 9]]

理想通りできました。
次にここから累積和の配列に仕上げていきます

1,2,3
4,5,6
7,8,9

このケースで行くと

S(y,x) = A[1][1] + A[1][2] + ... + A[1][x] + A[2][1] + ... + A[2][x] + ... + A[y][1] + ... + A[y][x]
S(1,1) = 1
S(1,2) = 1 + 2 = 3
S(1,3) = 1 + 2 + 3 = 6
S(2,1) = 1 + 4 = 5
S(2,2) = 1 + 2 + 4 + 5 = 12
S(2,3) = 1 + 2 + 3 + 4 + 5 + 6 = 21
S(3,1) = 1 + 4 + 7 = 13
S(3,2) = 1 + 2 + 4 + 5 + 7 + 8 = 27
S(3,3) = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 = 45

※図形で考えると良い。

1,3,6
5,12,21
12,27,45

で、たとえば(3,3)は
S(3,3) = S(3,2) + S(2,3) - S(2,2)
    = 27 + 21 - 12 + 9 = 45

どうしてこうなるかというと、図形を見ればわかるのだが
たとえばS(3,2)は
1 + 2 + 4 + 5 + 7 + 8

1 + 2 + 3 + 4 + 5 + 6

1 + 2 + 4 + 5


で不要な数字を除外するとあら不思議
1〜9の和になっている。
(不思議でもなんでもないが)

というわけでロジック化でき、以下のようになりました。

H, W, N = map(int, input().split())
A = [list(map(int,input().split())) for _ in range(N)]
#W*Hの配列に0を入れたものを作る(0の分だけ+1する)
ans = [[0] * (W + 1) for _ in range(H + 1)]

for i in range(1, H + 1):
    ans[i] = [0] + A[i - 1][:]
    #計算して入れていく(もともとある数字に累積和を入れていくので+=になる)
    for j in range(1, W + 1):
        ans[i][j] += ans[i - 1][j] + ans[i][j - 1] - ans[i - 1][j - 1]

#指定のものを出力する
for _ in range(N):
    y, x = map(int, input().split())
    print(ans[y][x])

これで行けるかと思ったら、
A配列の入れ方が悪かったようです。

H, W, N = map(int, input().split())
# #これだとNG
# A = [list(map(int,input().split())) for _ in range(N)]
#これだとOK
A = [[int(x) for x in input().split()] for _ in range(H)]
#W*Hの配列に0を入れたものを作る(0の分だけ+1する)
ans = [[0] * (W + 1) for _ in range(H + 1)]

for i in range(1, H + 1):
    ans[i] = [0] + A[i - 1][:]
    #計算して入れていく(もともとある数字に累積和を入れていくので+=になる)
    for j in range(1, W + 1):
        ans[i][j] += ans[i - 1][j] + ans[i][j - 1] - ans[i - 1][j - 1]

#指定のものを出力する
for _ in range(N):
    y, x = map(int, input().split())
    print(ans[y][x])

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0