문제링크 : https://www.acmicpc.net/problem/7453


아이디어

  • 접근 1. 배열 4개를 모든 경우의수로 더할경우
    • O(N^4) : 4000^4 > 시간초과
  • 접근 2. 두개씩 더해서 이진탐색 사용 가능할까?
    • 두개씩 더한다음
    • 한개만 정렬을 해줌
    • 그다음 각각 더해서 0이되는 수를 찾기
    • 0이 되는 여러개가 있을 수 있잖아 > 마지막에 같으면 여러개 구하기
    • 시간복잡도
      • 두개씩 곱함 : N^2 * 2
      • 한개 정렬 : N^2 * lgN^2
      • 모든 수에대해 더해서 0이되는 수를 이진탐색으로 찾기 : N^2 * lgN^2
      • 더해서 0이 되는거 여러개 있을경우, 계속 더해주기 : N
      • 총합 : O(N^2 * 2 + N^2 * lgN^2 + N*2 * lgN^2 * N) = O(N^3 * lgN^2) = 64e9 * 20 > 시간초과
  • 접근 3. 두개씩 더해서 투포인터 사용
    • 두개씩 더한 다음 모두 정렬
    • 각각의 배열에서 하나는 왼쪽(st)부터, 하나는 오른쪽(en)부터 시작해서 더해서 0이되는값 찾기
      • 더해서 0이 될경우, 각각 값이 같은 수 구해서 곱하기
      • 이떄, 더해서 0이될경우, 포인터 넘어가므로 O(N) 사용할 필요없음
    • 더해서 0보다 작을경우 st++, 클경우 en--

시간복잡도 계산

  • 두개 더한다음 정렬 : N^2 * 2 + N^2*lgN^2 * 2
  • 투포인터 수행 : N^2 * 2
  • 총합 : O(N^22 + N^2lgN^22 + N^22) = O(N^2*lgN^2)

자료구조

  • A,B,C,D 배열
    • 최대값 : 2^28 > INT 가능
  • 두개씩 더해준 값 : AB, CD
    • 최대값 : 2^29 > INT 가능
  • 합이 0이되는 쌍의 개수
    • 4000^4 > long long 사용

코드(C++)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <iostream>
#include <algorithm>
 
using namespace std;
typedef long long ll;
 
int A[4010];
int B[4010];
int C[4010];
int D[4010];
int AB[16000010];
int CD[16000010];
 
 
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    
    int n; cin >> n;
    for(int i=0; i<n; i++) {
        cin >> A[i] >> B[i] >> C[i] >> D[i];
    }
    
    // 두개씩 더하기
    int k=0;
    for(int j=0; j<n; j++) {
        for(int i=0; i<n; i++) {
            AB[k] = A[j] + B[i];
            CD[k] = C[j] + D[i];
            k++;
        }
    }
    
    // 정렬
    sort(AB, AB+k);
    sort(CD, CD+k);
    
    ll cnt=0;
 
    int st = 0;
    int en = k-1;
    
    while(st <&& en >=0) {
        int sumv =AB[st] + CD[en];
        if(sumv == 0) {
            // 두개가 같은게 여러개 있을 수 있음
            // 같은 값을 곱해서 더해주기
            int originSt = st;
            int sameSt = 0;
            while(AB[st] + CD[en] == 0) {
                sameSt++;
                st++;
                if(st==k) break;
            }
           
            int sameEn = 0;
            while(AB[originSt] + CD[en] == 0) {
                sameEn++;
                en--;
                if(en<0break;
            }
            cnt += sameSt * sameEn;
        } else if(sumv < 0) {
            st++;
        } else {
            en--;
        }
    }
    
    cout << cnt << '\n';
    return 0;
}
 
cs

문제유형

  • Two pointer - 두 배열의 pointer
    • 두배열의 합이나 곱으로 모든 경우의 수를 따져야할때
    • 양쪽에서 st, en놓고 올라가고 줄어드는 방법
    • 이때 조심해야할것 : 배열이 같은 값이 중복될 수 있음
    • 이떄 중복되는것 계산해줘야함

'알고리즘 > 백준' 카테고리의 다른 글

백준 18233 민준이와 마산 그리고 건우  (0) 2021.04.20
백준 1238 파티  (0) 2021.04.20
백준 2581 소수  (0) 2021.03.18
백준 12865 평범한 배낭  (0) 2021.03.18
백준 8983 사냥꾼  (0) 2021.03.18

+ Recent posts