[Boj_1208] ๋ถ€๋ถ„์ˆ˜์—ด์˜ ํ•ฉ 2

๐Ÿ“Ž ๋ฌธ์ œ ๋งํฌ

https://www.acmicpc.net/problem/1208

 

โ–ธ ๋ฌธ์ œ

N๊ฐœ์˜ ์ •์ˆ˜๋กœ ์ด๋ฃจ์–ด์ง„ ์ˆ˜์—ด์ด ์žˆ์„ ๋•Œ, ํฌ๊ธฐ๊ฐ€ ์–‘์ˆ˜์ธ ๋ถ€๋ถ„์ˆ˜์—ด ์ค‘์—์„œ ๊ทธ ์ˆ˜์—ด์˜ ์›์†Œ๋ฅผ ๋‹ค ๋”ํ•œ ๊ฐ’์ด S๊ฐ€ ๋˜๋Š” ๊ฒฝ์šฐ์˜ ์ˆ˜๋ฅผ ๊ตฌํ•˜๋Š” ํ”„๋กœ๊ทธ๋žจ์„ ์ž‘์„ฑํ•˜์‹œ์˜ค.

 

โ–ธ ์ž…๋ ฅ

์ฒซ์งธ ์ค„์— ์ •์ˆ˜์˜ ๊ฐœ์ˆ˜๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” N๊ณผ ์ •์ˆ˜ S๊ฐ€ ์ฃผ์–ด์ง„๋‹ค. (1 ≤ N ≤ 40, |S| ≤ 1,000,000) ๋‘˜์งธ ์ค„์— N๊ฐœ์˜ ์ •์ˆ˜๊ฐ€ ๋นˆ ์นธ์„ ์‚ฌ์ด์— ๋‘๊ณ  ์ฃผ์–ด์ง„๋‹ค. ์ฃผ์–ด์ง€๋Š” ์ •์ˆ˜์˜ ์ ˆ๋Œ“๊ฐ’์€ 100,000์„ ๋„˜์ง€ ์•Š๋Š”๋‹ค.

 

โ–ธ ์ถœ๋ ฅ

์ฒซ์งธ ์ค„์— ํ•ฉ์ด S๊ฐ€ ๋˜๋Š” ๋ถ€๋ถ„์ˆ˜์—ด์˜ ๊ฐœ์ˆ˜๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค.

 

๐Ÿ“ ๋ฌธ์ œ ์ •๋ณด

  • ๐Ÿฅ‡  ๋ฌธ์ œ ๋ ˆ๋ฒจ : ๊ณจ๋“œ 1
  • ๐Ÿ””  ๋ฌธ์ œ ์œ ํ˜• : ์ด๋ถ„ ํƒ์ƒ‰, ์ค‘๊ฐ„์—์„œ ๋งŒ๋‚˜๊ธฐ
  • ๐Ÿ’ฌ  ํ’€์ด ์–ธ์–ด : JAVA

 

๐Ÿค” ๋ฌธ์ œ ํ’€์ด

N๊ฐœ์˜ ์ •์ˆ˜๊ฐ€ ์ฃผ์–ด์กŒ์„ ๋•Œ, ํฌ๊ธฐ๊ฐ€ ์–‘์ˆ˜์ธ ๋ถ€๋ถ„์ˆ˜์—ด ์ค‘์—์„œ ์›์†Œ ํ•ฉ์ด S๊ฐ€ ๋˜๋Š” ๊ฒฝ์šฐ์˜ ์ˆ˜๋ฅผ ๊ตฌํ•˜๋Š” ๋ฌธ์ œ์ด๋‹ค.

๋‹จ, N์€ ์ตœ๋Œ€ 40์ด๋ฏ€๋กœ ๋‹จ์ˆœํ•œ ๋ถ€๋ถ„์ง‘ํ•ฉ ํƒ์ƒ‰์œผ๋กœ๋Š” ์‹œ๊ฐ„ ์ดˆ๊ณผ ๊ฐ€๋Šฅ์„ฑ์ด ํฌ๋‹ค.

 

๊ทธ๋Ÿฌ๋ฏ€๋กœ Boj_1450 ๋ƒ…์ƒ™๋ฌธ์ œ์—๋„ ํ™œ์šฉํ–ˆ๋˜ ์ค‘๊ฐ„์—์„œ ๋งŒ๋‚˜๊ธฐ(Meet in the middle) ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

 

1๏ธโƒฃ ๋ฐฐ์—ด ๋‚˜๋ˆ„๊ธฐ

๋ฐฐ์—ด์„ ๋ฐ˜์œผ๋กœ ๋‚˜๋ˆ„๊ณ , ๊ฐ ์ ˆ๋ฐ˜์—์„œ ๊ฐ€๋Šฅํ•œ ๋ถ€๋ถ„์ง‘ํ•ฉ์˜ ํ•ฉ์„ ์ „๋ถ€ ๋ฆฌ์ŠคํŠธ์— ์ €์žฅํ•œ๋‹ค.

์ด๋•Œ, ์žฌ๊ท€ ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ๋ชจ๋“  ์กฐํ•ฉ์„ ํƒ์ƒ‰ํ•œ๋‹ค.

private static void comb(int start, int end, ArrayList<Integer> list, int sum) {
    if (start == end) {
        list.add(sum);
        return;
    }

    comb(start+1, end, list, sum+arr[start]); // ํ˜„์žฌ ์›์†Œ ํฌํ•จ
    comb(start+1, end, list, sum); // ํ˜„์žฌ ์›์†Œ ๋ฏธํฌํ•จ
}
  • start๋ถ€ํ„ฐ end ์ „๊นŒ์ง€ ๋ชจ๋“  ๋ถ€๋ถ„์ง‘ํ•ฉ์˜ ํ•ฉ์„ ๊ตฌํ•ด list์— ์ €์žฅํ•œ๋‹ค.
  • ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์™ผ์ชฝ ์ ˆ๋ฐ˜(left)์™€ ์˜ค๋ฅธ์ชฝ ์ ˆ๋ฐ˜(right)์˜ ๋ชจ๋“  ๋ถ€๋ถ„์ง‘ํ•ฉ์˜ ํ•ฉ์„ ๊ตฌํ•  ์ˆ˜ ์žˆ๋‹ค.

 

2๏ธโƒฃ ๋‘ ๋ฆฌ์ŠคํŠธ์˜ ์กฐํ•ฉ์œผ๋กœ S ๋งŒ๋“ค๊ธฐ

์™ผ์ชฝ ๋ฆฌ์ŠคํŠธ์˜ ๊ฐ ์›์†Œ x์— ๋Œ€ํ•ด, ์˜ค๋ฅธ์ชฝ ๋ฆฌ์ŠคํŠธ์—์„œ S-x๊ฐ€ ๋ช‡ ๋ฒˆ ๋“ฑ์žฅํ•˜๋Š”์ง€๋ฅผ ์ฐพ์•„ ์นด์šดํŠธํ•œ๋‹ค.

์ด๋ฅผ ํšจ์œจ์ ์œผ๋กœ ํ•˜๊ธฐ ์œ„ํ•ด ์˜ค๋ฅธ์ชฝ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ •๋ ฌํ•œ ๋’ค, ์ด์ง„ ํƒ์ƒ‰์„ ์‚ฌ์šฉํ•œ๋‹ค.

 

3๏ธโƒฃ ์ด์ง„ ํƒ์ƒ‰, lower_bound์™€ upper_bound

private static int upperBound(ArrayList<Integer> list, int target) {
    int left = 0;
    int right = list.size();

    while (left < right) {
        int mid = (left+right)/2;

        if (list.get(mid) <= target) left = mid+1;
        else right = mid;
    }

    return right;
}

private static int lowerBound(ArrayList<Integer> list, int target) {
    int left = 0;
    int right = list.size();

    while (left < right) {
        int mid = (left+right)/2;

        if (list.get(mid) >= target) right = mid;
        else left = mid+1;
    }

    return right;
}
  • lowerBound : target ์ด์ƒ์ด ์ฒ˜์Œ ๋‚˜์˜ค๋Š” ์œ„์น˜
  • upperBound : target ์ดˆ๊ณผ๊ฐ€ ์ฒ˜์Œ ๋‚˜์˜ค๋Š” ์œ„์น˜
  • ์ •๋ ฌ๋œ ๋ฆฌ์ŠคํŠธ์ผ ๋•Œ, upperBound - lowerBound๊ฐ€ target์˜ ๋“ฑ์žฅ ํšŸ์ˆ˜๊ฐ€ ๋œ๋‹ค.

 

โš ๏ธ ๊ณต์ง‘ํ•ฉ ์ฒ˜๋ฆฌ

๊ฐ ๋ฆฌ์ŠคํŠธ (left, right)์—๋Š” ๊ณต์ง‘ํ•ฉ ํ•ฉ(0)์ด ํฌํ•จ๋œ๋‹ค.

๋ฌธ์ œ์—์„œ ํฌ๊ธฐ๊ฐ€ ์–‘์ˆ˜์ธ ๋ถ€๋ถ„์ˆ˜์—ด๋งŒ ์„ธ์•ผ ํ•˜๋ฏ€๋กœ, S==0์ธ ๊ฒฝ์šฐ์—๋Š” ๋‘ ๊ณต์ง‘ํ•ฉ์„ ๋™์‹œ์— ์„ ํƒํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ๋นผ์ฃผ์–ด์•ผ ํ•œ๋‹ค.

 

์œ„ ํ’€์ด์˜ ์ฝ”๋“œ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์ „์ฒด์ ์ธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด ๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

 

โœ” ์ฝ”๋“œ

๋ฉ”๋ชจ๋ฆฌ : 80096KB
์‹œ๊ฐ„ : 1268ms
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.StringTokenizer;

public class Main {
    static int[] arr;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        int n = Integer.parseInt(st.nextToken());
        int s = Integer.parseInt(st.nextToken());

        arr = new int[n];
        st = new StringTokenizer(br.readLine());
        for (int i = 0; i < n; i++) {
            arr[i] = Integer.parseInt(st.nextToken());
        }

        ArrayList<Integer> left = new ArrayList<>();
        ArrayList<Integer> right = new ArrayList<>();
        comb(0, n/2, left, 0);
        comb(n/2, n, right, 0);
        Collections.sort(right);

        long ans = 0;
        for (int i = 0; i < left.size(); i++) {
            int target = s-left.get(i);
            int upper = upperBound(right, target);
            int lower = lowerBound(right, target);
            ans += upper - lower;
        }

        System.out.println(s == 0 ? ans-1 : ans);

        br.close();
    }

    private static int upperBound(ArrayList<Integer> list, int target) {
        int left = 0;
        int right = list.size();

        while (left < right) {
            int mid = (left+right)/2;

            if (list.get(mid) <= target) left = mid+1;
            else right = mid;
        }

        return right;
    }

    private static int lowerBound(ArrayList<Integer> list, int target) {
        int left = 0;
        int right = list.size();

        while (left < right) {
            int mid = (left+right)/2;

            if (list.get(mid) >= target) right = mid;
            else left = mid+1;
        }

        return right;
    }

    private static void comb(int start, int end, ArrayList<Integer> list, int sum) {
        if (start == end) {
            list.add(sum);
            return;
        }

        comb(start+1, end, list, sum+arr[start]);
        comb(start+1, end, list, sum);
    }
}