"""TC: O(1), SC: O(n^2)

-n <= a, b <= n 가정.
문제에서는 n이 1000으로 주어져있다고 볼 수 있다.

아이디어:
덧셈을 못 쓰게 한다면 전처리를 통해 모든 a, b 조합에 대한 덧셈 값을 만들어놓고 a, b의 값에 따라서
필요한 값을 출력하도록 하자. python에서는 음수로 된 인덱스를 지원하므로 이를 활용하자.

- 아래의 코드를 통해서 전처리된 값을 준비한다. 이 코드는 leetcode에서 실행되지 않으므로 더하기를
  써도 상관 없다.
```py
n = 3
with open("foo.txt", "w") as f:
    a = [
        [
            (i if i <= n else i - 2 * n - 1) + (j if j <= n else j - 2 * n - 1)
            for j in range(0, 2 * n + 1)
        ]
        for i in range(0, 2 * n + 1)
    ]
    f.write(str(a))
```

SC:
- O(n^2). 정확히는, (2*n+1)^2 개의 정수를 배열에 저장한다.

TC:
- 인덱스를 통해 바로 접근. O(1).
"""


class Solution:
    # n = 3일때 예시.
    def getSum(self, a: int, b: int) -> int:
        x = [
            [0, 1, 2, 3, -3, -2, -1],
            [1, 2, 3, 4, -2, -1, 0],
            [2, 3, 4, 5, -1, 0, 1],
            [3, 4, 5, 6, 0, 1, 2],
            [-3, -2, -1, 0, -6, -5, -4],
            [-2, -1, 0, 1, -5, -4, -3],
            [-1, 0, 1, 2, -4, -3, -2],
        ]
        return x[a][b]


# 단, n = 1000일때 이런 식으로 코드를 짜려고 하면
# `For performance reasons, the number of characters per line is limited to 10,000.`
# 하는 문구와 함께 리스트를 복붙할 수가 없다...


"""TC: O(n), SC: O(n)

-n <= a, b <= n 가정.
문제에서는 n이 1000으로 주어져있다고 볼 수 있다.

아이디어:
전처리 한 것을 가져오는 방법은 못 쓰게 되었지만, 인덱스를 통한 접근은 아직 그대로 쓰고 싶다.

- 문제의 조건을 바꿔서 0 <= a, b <= n라고 해보자. 그리고 n이 3이라고 해보자.
- a가 0으로 고정되어 있다면, 다음과 같은 배열이 주어졌을때 a+b의 값을 인덱스로 접근할 수 있다.
    - v = [0, 1, 2, 3] 일때 a + b 값은 v[b]
- a가 1로 고정되어 있다면,
    - v = [1, 2, 3, 4] 일때 a + b 값은 v[b]
- a가 2로 고정되어 있다면,
    - v = [2, 3, 4, 5] 일때 a + b 값은 v[b]
- a가 3으로 고정되어 있다면,
    - v = [3, 4, 5, 6] 일때 a + b 값은 v[b]
- 위의 배열을 보면 겹치는 숫자들이 많다. 그렇다면 0~6까지 숫자들이 들어있는 배열을 slicing해서
  쓰면 되지 않을까?
    - a가 0일때 v = [0, 1, 2, 3, 4, 5, 6] 중
                    [0, 1, 2, 3] 사용.
      즉, v[0:4] 사용.

    - a가 1일때 v = [0, 1, 2, 3, 4, 5, 6] 중
                       [1, 2, 3, 4] 사용.
      즉, v[1:5] 사용.
    ...
    - 일반화하면, v[a:a+n+1] 사용. 이때 a+b 값은 v = list(range(0, 2 * n + 1))일때 v[a:a+n+1][b].
- 그런데 v[a:a+n+1][b]를 보면 슬라이싱 하는 부분에서 + 기호를 사용했다.
    - 그렇다면 저기서 더하기 기호를 사용할 필요 없이 슬라이싱의 시작 값과 끝 값도 미리 리스트로 만들고,
      이 리스트에서 a번째 아이템을 가져오는 방식을 활용해보자.
    - s = [0, 1, 2, 3], e = [4, 5, 6, 7]일때, v[a:a+n+1][b] = v[s[a]:e[a]][b]가 된다.
    - 일반화하면, s = list(range(0, n)), e = list(range(n+1, 2*n+1))이면 된다.
    - e를 만들면서 더하기를 쓴 것처럼 보이지만, 실제로는 n이 주어진 상수이므로 값을 계산해서 넣으면 된다.
    - 예를 들어, n=3일때 e = list(range(4, 7))이다.

큰 아이디어는 위의 방식으로 설명이 끝났다. 이제 문제는 0 <= a, b <= n이 아니라 -n <= a, b <= n 범위에서도
위의 방식이 작동하도록 하는 것인데, 먼저 a값은 양수 범위에 두고 b값만 음수로 확장한 상태에서 v를 구해보고,
그 다음 a도 음수까지 확장하는 식으로 접근하면 된다. 자세한 설명은 생략하고, 둘 다 음수 범위까지 확장한 뒤
실제로 작동하는 결과물을 설명하는 것으로 대신하겠다.

- n은 3이라고 가정하겠다.
- v = [0, 1, 2, 3, 4, 5, 6, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, -6, -5, -4, -3, -2, -1]
    - list(range(0, n+1))에 list(range(-n, 0))을 이어붙인 것을 두 번 반복했다.
    - 두 번 반복한 이유는 a값이 음수가 된 상황에 대응하기 위함이다. 아래의 설명을 이어서 보도록 하자.
- s = list(range(0, 4 * n + 1)) = list(range(0, 13))이다.
    - 이렇게 하면 a가 음수가 되었을때도 slicing을 시작할 인덱스는 양수로 유지할 수 있다.
    - b를 0으로 고정하면 slicing을 시작하는 인덱스에 있는 아이템이 a+b의 값이 되어야 한다.
    - 이를 위의 v와 같이 생각하면 v의 앞 13개 아이템을 취한 [0, 1, 2, 3, 4, 5, 6, -6, -5, -4, -3, -2, -1]
      배열이 있을때 a가 취할 수 있는 값의 범위는 -3~3이므로 [0, 1, 2, 3, ..., -3, -2, -1] 중 하나부터
      slicing이 시작된다고 보면 된다.
    - 그러니까 쉽게 말해서 a의 범위로 인해 slicing이 아이템 4부터 시작해서 [4, 5, 6, -6, ...] 하는 일이
      일어나지는 않는다는 뜻.      
- slicing한 배열의 크기는 4*n+1이어야 한다. e는 s의 각 아이템에 4*n+1을 더한 값이면 된다.
    - 4*n+1은 관찰을 통해 얻을 수 있는 값이다.a, b의 합의 최소가 -2*n, 최대가 2*n이어서 그 사이에 있는
      숫자들이 총 4*n+1개 있다는 것에서 비롯된 숫자다.
        - 끝에 예시를 보면 이해가 좀 더 편하다.
    - 정리하면, e = list(range(4*n+1, 8*n+2)) = list(range(13, 26))이다.
- a+b 값은 v[s[a] : e[a]][b] 로 구할 수 있다.
- 예를 들어, a=2, b=-3이라고 할때
    - v[s[a] : e[a]] = v[2:15] = [2, 3, 4, 5, 6, -6, -5, -4, -3, -2, -1, 0, 1]다.
    - b가 -3이므로 위의 slicing된 배열에서 뒤에서 세 번째 아이템을 찾으면 된다. 즉, -1이다.
    - 잘 관찰하면 덧셈의 결과가 될 수 있는 값은 [2, 3, 4, 5, ..., -1, 0, 1] 밖에 없다. 사이에 있는 숫자는
      b의 범위가 제한되어 있어서 접근 불가능한, 즉, 필요 없는 숫자들이라고 보면 된다.

SC:
- 코드 참조. O(n).

TC:
- 인덱스를 통해 바로 접근. O(1).
"""


class Solution:
    def getSum(self, a: int, b: int) -> int:
        x = list(range(0, 2001))
        x.extend(list(range(-2000, 0)))
        v = x * 2  # SC: O(n)
        s = list(range(0, 4001))  # SC: O(n)
        e = list(range(4001, 8002))  # SC: O(n)
        return v[s[a] : e[a]][b]
