※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 2143번 문제인 두 배열의 합이다.
문제는 아래 링크를 확인하자.

www.acmicpc.net/problem/2143

 

2143번: 두 배열의 합

첫째 줄에 T(-1,000,000,000 ≤ T ≤ 1,000,000,000)가 주어진다. 다음 줄에는 n(1 ≤ n ≤ 1,000)이 주어지고, 그 다음 줄에 n개의 정수로 A[1], …, A[n]이 주어진다. 다음 줄에는 m(1≤m≤1,000)이 주어지고, 그 다

www.acmicpc.net

각 배열 A, B의 크기는 최대 1000으로 그리 큰 숫자가 아니라는 것에 주목하자.

이 문제에 사용되는 연산은 대부분 간단한 덧셈의 반복이므로, 모든 A의 구간합과 B의 구간합을 구해 같은 쌍을 찾아주어도 무리가 없다.

 

1~n, 2~n, 3~n, ... (n-1)~n, n~n의 범위의 합을 각각 저장해두면, index n+1 이하 범위에서 나올 수 있는 구간합은 n+1번째 원소 자신과, 구해진 앞쪽 범위의 n을 포함하는 구간합에 n+1번째 원소를 각각 더한 것들으로 전부 구할 수 있다. 이를 이용하여 구간합의 배열을 각각 만든다. 이 때, B의 구간합을 T에서 뺀 값을 저장한다면, 이 문제는 같은 값들의 쌍을 구하는 문제로 간단히 바뀐다.

 

그 다음으로, 두 배열을 정렬한다. 마지막으로 각 배열의 index를 가리키는 두 포인터 ptA, ptB를 만들어, index 0에서부터 두 배열을 다음과 같이 탐색한다.

 

1) ptA가 가리키는 A쪽 구간합배열값이 ptB가 가리키는 B쪽 구간합배열값보다 작다면 ptA++, 크다면 ptB++

2) 둘이 같다면, A쪽 구간합배열에 그 수가 안 나올 때까지 ptA++을 하며 A쪽 구간합배열에 그 수가 들어있는 개수 cntA를 구한다. B쪽도 마찬가지로 ptB++를 하며 B쪽 구간합배열에 그 수가 들어있는 개수 cntB를 구한다. 출력할 답 변수에 cntA * cntB를 더해준다. [cntA * cntB의 값이 int 범위를 넘어갈 수 있음에 유의하자.]

3) ptA 또는 ptB가 각 배열의 범위를 넘어설 수 있다는 것을 유의하며 위 과정을 반복한다.

 

아래는 제출한 소스코드이다.

#include <iostream>
#include <algorithm>
using std::cin;
using std::cout;
using std::sort;

int A[1000];
int B[1000];
int prefixsumA[1000000];
int prefixsumB[1000000];

int main()
{
    std::ios::sync_with_stdio(0);
    cin.tie(0);

    int T;
    cin >> T;
    int N;
    cin >> N;
    int index1 = 0;
    for (int i = 0;i < N;i++) { // A의 구간합 배열 만들기
        int x;
        cin >> x;
        for (int j = 0;j <= i;j++) {
            A[j] += x;
            prefixsumA[index1] = A[j];
            index1++;
        }
    }
    int index2 = 0;
    cin >> N;
    for (int i = 0;i < N;i++) { // B의 (T - 구간합) 배열 만들기
        int x;
        cin >> x;
        for (int j = 0;j <= i;j++) {
            B[j] += x;
            prefixsumB[index2] = T - B[j];
            index2++;
        }
    }
    sort(prefixsumA, prefixsumA + index1); // 정렬
    sort(prefixsumB, prefixsumB + index2);
    int ptA = 0; // Two Pointer
    int ptB = 0;
    long long ans = 0;
    while (ptA < index1 and ptB < index2) {
        int AA = prefixsumA[ptA];
        int BB = prefixsumB[ptB];
        if (AA < BB) ptA++;
        else if (AA > BB) ptB++;
        else {
            long long cntA = 0;
            long long cntB = 0;
            while (prefixsumA[ptA] == AA) {
                ptA++;
                cntA++;
                if (ptA >= index1) break;
            }
            while (prefixsumB[ptB] == BB) {
                ptB++;
                cntB++;
                if (ptB >= index2) break;
            }
            ans += cntA * cntB;
        }
    }

    cout << ans;

    return 0;
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 1753 // C++] 최단경로  (0) 2021.02.11
[BOJ 14502 // C++] 연구소  (0) 2021.02.10
[BOJ 13398 // C++] 연속합 2  (0) 2021.02.08
[BOJ 14686 // C++] Sum Game  (0) 2021.02.07
[BOJ 1107 // C++] 리모컨  (0) 2021.02.06

+ Recent posts