주어진 예시를 보면 줄 세우기 과정은 아래와 같다.

3 7 5 2 6 1 4

3 7 4 5 2 6 1

3 4 5 2 6 1 7

1 3 4 5 2 6 7

 

즉, 제자리에 있는 아이들의 번호는 아래와 같다. == LIS

3 7 5 2 6 1 4

 

import java.util.*;

public class Main {
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);

		int n = in.nextInt();
		int child[] = new int[n + 1];
		int ans[] = new int[n + 1];
		for (int i = 1; i <= n; i++) {
			child[i] = in.nextInt();
		}
		ans[1] = 1;

		for (int i = 2; i <= n; i++) {
			int max = 0;
			for (int j = 0; j < i; j++) {
				if (child[i] > child[j]) {
					max = Math.max(max, ans[j]);
				}
			}
			ans[i] = max + 1;
		}

		Arrays.sort(ans);
		System.out.println(n - ans[n]);
	}
}

오랜만에 코드 잼을 풀어볼까 해서 운동 갔다온 후 켰음. 역시 영어라서 문제푸는 시간보다 해석하는데 더 오래걸림ㅠ 영어공부 좀 해야겟다

코드잼 Qualification 라운드는 30점만 넘기면 다음 라운드에 참가할 수 있다.

 

Reversort

주어진 reversort 슈도 코드를 시키는대로 구현하면 되는 문제였다

import java.util.*;

public class Solution {

	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		int testcase = in.nextInt();
		for (int t = 1; t <= testcase; t++) {
			int n = in.nextInt();
			int[] arr = new int[n];
			for (int i = 0; i < n; i++) {
				arr[i] = in.nextInt();
			}

			int answer = 0;
			for (int i = 0; i < arr.length - 1; i++) {
				int j = minIndex(i, arr);
				reverse(i, j, arr);

				answer += (j - i + 1);
			}

			System.out.println("Case #" + t + ": " + answer);
		}
	}

	private static void reverse(int start, int end, int[] arr) {
		for (int i = 0; i <= (end - start) / 2; i++) {
			int temp = arr[start + i];
			arr[start + i] = arr[end - i];
			arr[end - i] = temp;
		}
	}

	private static int minIndex(int start, int[] arr) {
		int index = start;
		int value = arr[start];
		for (int i = start; i < arr.length; i++) {
			if (value > arr[i]) {
				value = arr[i];
				index = i;
			}
		}
		return index;
	}
}

 

Moons and Umbrellas

CJ가 나타나면 값x, JC가 나타나면 값y를 지불할 때 가장 작은 값을 리턴하는 문제이다.

일단은.. 테스트셋 2까지만 맞추는 것을 목표로 문제를 풀었다.

변수 범위는 아래와 같다.

1≤S.length()≤1000
1≤X≤100
1≤Y≤100

?가 있을 수 있는 값은 1000가지이고 모든 경우에 대해 구할 때 2^1000이 나와버리기 때문에 DP를 사용해야겠다고 생각했다.

dp[i][0]: 인덱스 i 가 ?일때, C를 넣을때 최솟값

dp[i][1]: 인덱스 i 가 ?일때, J를 넣을 때 최솟값으로 두고 아래와 같은 방식으로 풀어보기로 했다.

 

 

if-else, case문이 넘 드러워서 좀 간단히 할 수 있을 것 같긴 하지만... 일단 제출한 풀이는 아래와 같다.

import java.util.*;

public class Solution {

	private static final int C = 0;
	private static final int J = 1;

	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		int testcase = in.nextInt();
		for (int t = 1; t <= testcase; t++) {
			int x = in.nextInt(); // CJ
			int y = in.nextInt(); // JC
			char[] input = in.next().toCharArray();
			int length = input.length;

			int dp[][] = new int[length][2];
			for (int i = 1; i < length; i++) {
				if (input[i] == '?') {
					switch (input[i - 1]) {
					case '?':
						dp[i][C] = Math.min(dp[i - 1][C], dp[i - 1][J] + y);
						dp[i][J] = Math.min(dp[i - 1][J], dp[i - 1][C] + x);
						break;
					case 'C':
						dp[i][C] = dp[i - 1][C];
						dp[i][J] = dp[i - 1][C] + x;
						break;
					case 'J':
						dp[i][C] = dp[i - 1][J] + y;
						dp[i][J] = dp[i - 1][C];
						break;
					}
				} else if (input[i] == 'C') {
					switch (input[i - 1]) {
					case '?':
						dp[i][C] = Math.min(dp[i - 1][C], dp[i - 1][J] + y);
						dp[i][J] = Math.min(dp[i - 1][C], dp[i - 1][J] + y);
						break;
					case 'C':
						dp[i][C] = dp[i - 1][C];
						dp[i][J] = dp[i - 1][J];
						break;
					case 'J':
						dp[i][C] = dp[i - 1][C] + y;
						dp[i][J] = dp[i - 1][J] + y;
						break;
					}
				} else { // input[i] == 'J'
					switch (input[i - 1]) {
					case '?':
						dp[i][C] = Math.min(dp[i - 1][C] + x, dp[i - 1][J]);
						dp[i][J] = Math.min(dp[i - 1][C] + x, dp[i - 1][J]);
						break;
					case 'C':
						dp[i][C] = dp[i - 1][C] + x;
						dp[i][J] = dp[i - 1][J] + x;
						break;
					case 'J':
						dp[i][C] = dp[i - 1][C];
						dp[i][J] = dp[i - 1][J];
						break;
					}
				}
			}
			System.out.println("Case #" + t + ": " + Math.min(dp[length - 1][0], dp[length - 1][1]));
		}
	}
}

 

Reversort Engineering

요번에는 1번 Reversort와 달리 cost가 주어지면 리스트를 찾는 문제이다. 불가능하면 IMPOSSIBLE을 리턴하도록 한다.

일단 테스트셋 1의 경우 2N7이므로 permutation을 모두 구한 뒤 cost를 계산하고, 알맞은지 알아보도록 했다.

(이렇게 풀면 당연히 테스트셋2는 2N≤100이기 때문에 TLE가 나온다... 어떻게 해야하는지 모르겟음.. cost를 적당히 합으로 나눠서 리스트를 만드는건가.. 나중에 다른 사람들 풀이 봐야겟다..)

import java.util.*;

public class Solution {

	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		int testcase = in.nextInt();
		for (int t = 1; t <= testcase; t++) {
			int n = in.nextInt();
			int cost = in.nextInt();

			int[] arr = new int[n];
			for (int i = 0; i < n; i++) {
				arr[i] = i + 1;
			}

			boolean isPossible = calculateCost(arr) == cost;

			// create permutations
			while (!isPossible) {
				int idex = findIndex(arr, n);
				if (idex == -1) {
					break;
				}

				int jdex = 0;
				for (int j = n - 1; j >= idex; j--) {
					if (arr[j] > arr[idex - 1]) {
						jdex = j;
						break;
					}
				}

				int temp = arr[jdex];
				arr[jdex] = arr[idex - 1];
				arr[idex - 1] = temp;

				int brr[] = new int[n];
				int bindex = 0;
				for (int i = 0; i < idex; i++) {
					brr[bindex++] = arr[i];
				}
				for (int i = n - 1; i >= idex; i--) {
					brr[bindex++] = arr[i];
				}
				if (calculateCost(brr) == cost) {
					isPossible = true;
					arr = brr;
					break;
				}
				arr = brr;
			}
			System.out.print("Case #" + t + ": ");
			printAnswer(arr, isPossible);
		}
	}

	private static int findIndex(int arr[], int n) {
		for (int i = n - 1; i >= 1; i--) {
			if (arr[i - 1] < arr[i])
				return i;
		}
		return -1;
	}

	private static int[] clone(int[] list) {
		int[] newList = new int[list.length];
		for (int i = 0; i < list.length; i++) {
			newList[i] = list[i];
		}
		return newList;
	}

	private static int calculateCost(int[] arr) {
		int[] list = clone(arr);
		int answer = 0;
		for (int i = 0; i < list.length - 1; i++) {
			int j = minIndex(i, list);
			reverse(i, j, list);

			answer += (j - i + 1);
		}
		return answer;
	}

	private static void reverse(int start, int end, int[] arr) {
		for (int i = 0; i <= (end - start) / 2; i++) {
			int temp = arr[start + i];
			arr[start + i] = arr[end - i];
			arr[end - i] = temp;
		}
	}

	private static int minIndex(int start, int[] arr) {
		int index = start;
		int value = arr[start];
		for (int i = start; i < arr.length; i++) {
			if (value > arr[i]) {
				value = arr[i];
				index = i;
			}
		}
		return index;
	}

	private static void printAnswer(int[] answer, boolean isPossible) {
		if (!isPossible) {
			System.out.println("IMPOSSIBLE");
			return;
		}

		for (int a : answer) {
			System.out.print(a + " ");
		}
		System.out.println();
	}
}

 

 

여기까지.. 31점을 얻었다 일단은..

 

'알고리즘 공부' 카테고리의 다른 글

SWEA 1248: 공통조상  (0) 2021.01.17
SWEA 3462: 선표의 축구 경기 예측  (0) 2021.01.10
SWEA 1949: 등산로 조성  (0) 2021.01.07
SWEA 1267: 작업순서  (0) 2021.01.03
SWEA 5653: 줄기세포 배양  (0) 2021.01.03

문제 조건

  • 1 ≤ 신이 좋아하는 문자열의 길이 ≤ 5
  • 1 ≤ K ≤ 1,000, K는 자연수이다.

 

처음에는 문자열 길이만 보고 거의 완탐으로 문제를 풀었는데, 시간 초과가 났다

DP인가 했지만 이미 지나 왔던 칸들을 다시 방문하는 것은 허용한다고 했기 때문에 불가능 하고,

갈 수 있는 방향을 모두 탐색하는 대신 map으로 다음 문자열과 같은 곳만 탐색하도록 하는 방법을 사용했다.

이를 적용한 `틀린` 코드는 아래와 같다. => 이렇게 풀면 최악일 때 10* 10 * 1000 * 5^8 이 나온다

import java.util.*;

public class Main {

	private static int dr[] = { -1, -1, 0, 1, 1, 1, 0, -1 };
	private static int dc[] = { 0, -1, -1, -1, 0, 1, 1, 1 };

	private static int sum = 0;

	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);

		int row = in.nextInt();
		int col = in.nextInt();
		int testcase = in.nextInt();
		char[][] alphabets = new char[row + 1][col + 1];
		HashMap<Character, HashSet<Position>> map[][] = new HashMap[row + 1][col + 1];
		for (int i = 1; i <= row; i++) {
			String rowInput = in.next();
			for (int j = 1; j <= col; j++) {
				alphabets[i][j] = rowInput.charAt(j - 1);
				map[i][j] = new HashMap<Character, HashSet<Position>>();
			}
		}

		for (int i = 1; i <= row; i++) {
			for (int j = 1; j <= col; j++) {
				for (int d = 0; d < 8; d++) {
					int newRow = i + dr[d];
					int newCol = j + dc[d];

					if (newRow < 1) {
						newRow = row;
					}
					if (newCol < 1) {
						newCol = col;
					}
					if (newRow > row) {
						newRow = 1;
					}
					if (newCol > col) {
						newCol = 1;
					}

					char ch = alphabets[newRow][newCol];

					if (map[i][j] == null) {
						map[i][j] = new HashMap<Character, HashSet<Position>>();
					}
					if (!map[i][j].containsKey(ch)) {
						map[i][j].put(ch, new HashSet<>());
					}
					map[i][j].get(ch).add(new Position(newRow, newCol));
				}
			}
		}

		for (int t = 0; t < testcase; t++) {
			char[] favorite = in.next().toCharArray();
			int length = favorite.length;
			sum = 0;

			for (int i = 1; i <= row; i++) {
				for (int j = 1; j <= col; j++) {
					if (favorite[0] == alphabets[i][j]) {
						findAll(1, i, j, favorite, length, row, col, alphabets, map);
					}
				}
			}

			System.out.println(sum);
		}
	}

	private static void findAll(int index, int row, int col, char[] target, int targetLength, int maxRow, int maxCol,
			char[][] alphabets, HashMap<Character, HashSet<Position>> map[][]) {
		if (index == targetLength) {
			sum++;
			return;
		}

		HashSet<Position> set = map[row][col].get(target[index]);
		if (set != null) {

			for (Position p : set) {
				int newRow = p.row;
				int newCol = p.col;

				findAll(index + 1, newRow, newCol, target, targetLength, maxRow, maxCol, alphabets, map);
			}
		}
	}
}

class Position {
	int row, col;

	public Position(int row, int col) {
		this.row = row;
		this.col = col;
	}
}

 

 

 

그래서 어차피 완전 탐색은 한 번은 꼭 해야 할텐데 방문했을 때 생긴 문자열의 수를 각각 구해서 저장한 뒤,

문자열을 입력받을 때마다 바로 리턴하는 방식으로 바꾸기로 했다. 이렇게 될 경우 시간 복잡도는 O(10* 10 * 5^8) 으로 줄어들게 된다.

import java.io.*;
import java.util.*;

public class Main {

	private static final int dr[] = { -1, -1, 0, 1, 1, 1, 0, -1 };
	private static final int dc[] = { 0, -1, -1, -1, 0, 1, 1, 1 };

	private static final int MAX_LENGTH = 5;

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());

		int row = Integer.parseInt(st.nextToken());
		int col = Integer.parseInt(st.nextToken());
		int testcase = Integer.parseInt(st.nextToken());
		char[][] alphabets = new char[row + 1][col + 1];
		HashMap<String, Integer> map = new HashMap<>();
		for (int i = 1; i <= row; i++) {
			String rowInput = br.readLine();
			for (int j = 1; j <= col; j++) {
				alphabets[i][j] = rowInput.charAt(j - 1);
			}
		}

		for (int i = 1; i <= row; i++) {
			for (int j = 1; j <= col; j++) {
				String createdString = Character.toString(alphabets[i][j]);
				map.put(createdString, map.getOrDefault(createdString, 0) + 1);
				findAll(1, i, j, row, col, map, createdString, alphabets);
			}
		}

		for (int t = 0; t < testcase; t++) {
			String favorite = br.readLine();
			System.out.println(map.getOrDefault(favorite, 0));
		}
	}

	private static void findAll(int index, int row, int col, int maxRow, int maxCol, HashMap<String, Integer> map,
			String createdString, char[][] alphabets) {
		if (index == MAX_LENGTH) {
			return;
		}

		for (int d = 0; d < 8; d++) {
			int newRow = row + dr[d];
			int newCol = col + dc[d];

			if (newRow < 1) {
				newRow = maxRow;
			}
			if (newCol < 1) {
				newCol = maxCol;
			}
			if (newRow > maxRow) {
				newRow = 1;
			}
			if (newCol > maxCol) {
				newCol = 1;
			}

			String newCreatedString = createdString + alphabets[newRow][newCol];
			map.put(newCreatedString, map.getOrDefault(newCreatedString, 0) + 1);
			findAll(index + 1, newRow, newCol, maxRow, maxCol, map, newCreatedString, alphabets);
		}
	}
}

 

 

'알고리즘 공부 > boj' 카테고리의 다른 글

boj 2631: 줄세우기  (0) 2021.04.01
boj 20165: 인내의 도미노 장인 호석  (0) 2021.03.24
boj 20164: 홀수 홀릭 호석  (0) 2021.03.24
boj 11663: 선분 위의 점  (0) 2021.03.17
boj 19637: IF문 좀 대신 써줘  (0) 2021.03.17

뭔가 문제가 삼성느낌이 난다...

문제 풀이 코드는 아래와 같다. 코드가 넘 긴 느낌이 있긴 하지만... 시키는 대로만 하면 풀 수 있다

import java.util.*;

public class Main {
	private static int STAND = 0;
	private static int FALL = 1;

	private static int[][] before;

	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);

		int R = in.nextInt();
		int C = in.nextInt();
		int round = in.nextInt();

		int mat[][] = new int[R][C];
		for (int i = 0; i < R; i++) {
			for (int j = 0; j < C; j++) {
				mat[i][j] = in.nextInt();
			}
		}

		before = new int[R][C]; // 0: 서 있음, 1: 넘어짐
		int score = 0;
		for (int r = 0; r < round; r++) {
			int attackR = in.nextInt() - 1;
			int attackC = in.nextInt() - 1;
			Direction direction = Direction.valueOf(in.next());

			int defendR = in.nextInt() - 1;
			int defendC = in.nextInt() - 1;
			score += turn(mat, attackR, attackC, direction, defendR, defendC, R, C);
		}

		System.out.println(score);
		print(before);
	}

	private static int turn(int mat[][], int attackR, int attackC, Direction direction, int defendR, int defendC,
			int maxRow, int maxCol) {
		int[][] after = clone(before, maxRow, maxCol);
		attack(mat, after, attackR, attackC, direction, maxRow, maxCol);
		int score = calculateScore(after, maxRow, maxCol);
		defend(after, defendR, defendC);

		before = after;
		return score;
	}

	private static void attack(int mat[][], int[][] after, int attackR, int attackC, Direction direction, int maxRow,
			int maxCol) {
		if (after[attackR][attackC] == FALL) {
			return;
		}

		after[attackR][attackC] = FALL;
		for (int i = 1; i < mat[attackR][attackC]; i++) {
			int newRow = attackR + direction.row * i;
			int newCol = attackC + direction.col * i;
			// System.out.println(newRow + " " + newCol + " " + direction.toString());
			if (isBoundary(newRow, newCol, maxRow, maxCol) && after[newRow][newCol] == STAND) {
				attack(mat, after, newRow, newCol, direction, maxRow, maxCol);
			}
		}
	}

	private static boolean isBoundary(int row, int col, int maxRow, int maxCol) {
		if (row < 0) {
			return false;
		}
		if (col < 0) {
			return false;
		}
		if (row >= maxRow) {
			return false;
		}
		if (col >= maxCol) {
			return false;
		}
		return true;
	}

	private static void defend(int[][] after, int defendR, int defendC) {
		after[defendR][defendC] = STAND;
	}

	private static int calculateScore(int after[][], int row, int col) {
		int sum = 0;

		for (int i = 0; i < row; i++) {
			for (int j = 0; j < col; j++) {
				if (before[i][j] == STAND && after[i][j] == FALL) {
					sum++;
				}
			}
		}
		return sum;
	}

	private static int[][] clone(int mat[][], int row, int col) {
		int newMat[][] = new int[row][col];

		for (int i = 0; i < row; i++) {
			for (int j = 0; j < col; j++) {
				newMat[i][j] = mat[i][j];
			}
		}

		return newMat;
	}

	private static void print(int mat[][]) {
		int row = mat.length;
		int col = mat[0].length;

		for (int i = 0; i < row; i++) {
			for (int j = 0; j < col; j++) {
				if (mat[i][j] == STAND) {
					System.out.print("S ");
				} else {
					System.out.print("F ");
				}
			}
			System.out.println();
		}
	}
}

enum Direction {
	N(-1, 0), W(0, -1), E(0, 1), S(1, 0);

	int row;
	int col;

	Direction(int row, int col) {
		this.row = row;
		this.col = col;
	}

	public String toString() {
		return this.name() + "(" + this.row + ", " + this.col + ")";
	}
}

'알고리즘 공부 > boj' 카테고리의 다른 글

boj 2631: 줄세우기  (0) 2021.04.01
boj 20166: 문자열 지옥에 빠진 호석  (1) 2021.03.26
boj 20164: 홀수 홀릭 호석  (0) 2021.03.24
boj 11663: 선분 위의 점  (0) 2021.03.17
boj 19637: IF문 좀 대신 써줘  (0) 2021.03.17

N의 범위는 10^9-1 까지이므로 8자리까지 들어올 수 있다.

가장 큰 수가 들어오는 경우를 생각해도 8자리를 3가지 뽑는 경우는 8C3 = 56가지이고,

재귀 함수의 깊이는 그렇게 깊지 않으므로 dp를 사용하지 않아도 될 것이라고 생각했다.

 

 

풀다가 한 가지 실수해서 테스트케이스에 걸린 부분이 있는데,

length 를 구할 때, 아무 생각 없이 Math.ceil로 구해버렸다가 테스트케이스 100 이 들어오면 length = 2가 되어버린다는 것을 깨달았다...

고친 풀이는 아래와 같다.

import java.util.*;

public class Main {

	private static int max = 0;
	private static int min = Integer.MAX_VALUE;

	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);

		int N = in.nextInt();
		findAll(N, calcOdds(N));
		System.out.println(min + " " + max);
	}

	private static void findAll(int num, int odd) {
		if (num < 10) {
			max = Math.max(max, odd);
			min = Math.min(min, odd);
			return;
		}

		if (num < 100) {
			int newNum = num / 10 + num % 10;
			int newOdd = calcOdds(newNum);
			findAll(newNum, odd + newOdd);
			return;
		}

		int length = (int) Math.floor(Math.log10(num)) + 1;
		for (int firstLength = 1; firstLength <= length - 2; firstLength++) {
			for (int secondLength = 1; secondLength <= length - firstLength - 1; secondLength++) {
				int thirdLength = length - firstLength - secondLength;

				int secondPow = (int) Math.pow(10, secondLength);
				int thirdPow = (int) Math.pow(10, thirdLength);

				int firstNum = num / secondPow / thirdPow;
				int secondNum = (num / thirdPow) % secondPow;
				int thirdNum = num % thirdPow;

				int newNum = firstNum + secondNum + thirdNum;
				int newOdd = calcOdds(newNum);
				findAll(newNum, odd + newOdd);
			}
		}
	}

	private static int calcOdds(int num) {
		int sum = 0;
		while (num != 0) {
			sum += (num % 10) % 2;
			num /= 10;
		}
		return sum;
	}
}

일단 아이디어 자체는 왼쪽에서 포함되는 점의 위치 leftIndex와 오른쪽에서 포함되는 점의 위치 rightIndex를 각각 구한 뒤,

rightIndex - leftIndex + 1 을 하여 구해 보자는 생각이었다.

import java.util.*;
import java.io.*;

public class Main {

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());

		int points = Integer.parseInt(st.nextToken());
		int lines = Integer.parseInt(st.nextToken());

		int point[] = new int[points];

		st = new StringTokenizer(br.readLine());
		for (int i = 0; i < points; i++) {
			point[i] = Integer.parseInt(st.nextToken());
		}
		Arrays.sort(point);

		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		for (int i = 0; i < lines; i++) {
			st = new StringTokenizer(br.readLine());
			int left = Integer.parseInt(st.nextToken());
			int right = Integer.parseInt(st.nextToken());

			int rightIndex = getRightIndex(right, points - 1, point);
			int leftIndex = getLeftIndex(left, points - 1, point);
			// System.out.println(leftIndex + " " + rightIndex);
			int sum = rightIndex - leftIndex + 1;
			sum = Math.max(0, sum);
			bw.write(sum + "\n");
		}
		bw.flush();
		br.close();
	}

	private static int getLeftIndex(int target, int length, int[] point) {
		int start = 0;
		int end = length;
		int answer = end;

		while (start <= end) {
			int mid = (start + end) / 2;

			if (target < point[mid]) {
				answer = Math.min(answer, mid);
				end = mid - 1;
			} else if (target == point[mid]) {
				return mid;
			} else {
				start = mid + 1;
			}
		}
		return answer;
	}

	private static int getRightIndex(int target, int length, int[] point) {
		int start = 0;
		int end = length;
		int answer = 0;

		while (start <= end) {
			int mid = (start + end) / 2;

			if (point[mid] < target) {
				answer = Math.max(answer, mid);
				start = mid + 1;
			} else if (point[mid] == target) {
				return mid;
			} else {
				end = mid - 1;
			}
		}
		return answer;
	}
}

 

하지만, 0이나 40과 같이 범위를 벗어나는 선분인 경우 따로 처리가 필요했다.

(예를 들어 선분 40 40 의 경우 기존 코드에서는 범위에 벗어난 선분이지만 점 1개를 리턴하고 있었다.)

import java.util.*;
import java.io.*;

public class Main {

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());

		int points = Integer.parseInt(st.nextToken());
		int lines = Integer.parseInt(st.nextToken());

		int point[] = new int[points];

		st = new StringTokenizer(br.readLine());
		for (int i = 0; i < points; i++) {
			point[i] = Integer.parseInt(st.nextToken());
		}
		Arrays.sort(point);

		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		for (int i = 0; i < lines; i++) {
			st = new StringTokenizer(br.readLine());
			int left = Integer.parseInt(st.nextToken());
			int right = Integer.parseInt(st.nextToken());

			int rightIndex = getRightIndex(right, points - 1, point);
			int leftIndex = getLeftIndex(left, points - 1, point);
			// System.out.println(leftIndex + " " + rightIndex);
			int sum = calcPoints(leftIndex, rightIndex, points);
			bw.write(sum + "\n");
		}
		bw.flush();
		br.close();
	}

	private static int calcPoints(int leftIndex, int rightIndex, int length) {
		if (rightIndex < 0 && leftIndex < 0) {
			return 0;
		}

		if (rightIndex >= length && leftIndex >= length) {
			return 0;
		}

		if (leftIndex < 0 && rightIndex >= length) {
			return length;
		}

		if (leftIndex < 0) {
			return rightIndex + 1;
		}

		if (rightIndex >= length) {
			return length - leftIndex;
		}

		return rightIndex - leftIndex + 1;
	}

	private static int getLeftIndex(int target, int length, int[] point) {
		int start = 0;
		int end = length;
		int answer = end;

		if (target < point[0]) {
			return -1;
		}
		if (point[end] < target) {
			return end + 1;
		}

		while (start <= end) {
			int mid = (start + end) / 2;

			if (target < point[mid]) {
				answer = Math.min(answer, mid);
				end = mid - 1;
			} else if (target == point[mid]) {
				return mid;
			} else {
				start = mid + 1;
			}
		}
		return answer;
	}

	private static int getRightIndex(int target, int length, int[] point) {
		int start = 0;
		int end = length;
		int answer = 0;

		if (target < point[0]) {
			return -1;
		}
		if (point[end] < target) {
			return end + 1;
		}

		while (start <= end) {
			int mid = (start + end) / 2;

			if (point[mid] < target) {
				answer = Math.max(answer, mid);
				start = mid + 1;
			} else if (point[mid] == target) {
				return mid;
			} else {
				end = mid - 1;
			}
		}

		return answer;
	}
}

이렇게 귀찮아질 바에는 반대로 생각하면 조금 더 쉬워진다. 지금은 포함되는 점의 시작점, 끝점을 구했지만

포함되지 않는 부분의 점들을 구하게 된다면 풀이는 조금 더 간단해 질 수 있음..

 

'알고리즘 공부 > boj' 카테고리의 다른 글

boj 20165: 인내의 도미노 장인 호석  (0) 2021.03.24
boj 20164: 홀수 홀릭 호석  (0) 2021.03.24
boj 19637: IF문 좀 대신 써줘  (0) 2021.03.17
boj 2805: 나무 자르기  (0) 2021.03.16
boj 2417: 정수 제곱근  (0) 2021.03.15

칭호는 전투력 상한값의 비내림차순으로 주어진다. = 오름차순 이란 말인가??

상당히 찝찝하지만... 오름차순으로 이해하고 문제를 풀었다.

 

이 문제에서 주의할 점은 입출력이 많기 때문에 내가 평소에 애용하는 Scanner/System.out.println을 써 버리면 시간초과가 난다는 점이다.

BufferedReader/BufferedWriter를 써버릇 해야 하는데.. 길고 귀찮아서 굳이 틀려야 바꿔보게 된다... 담엔 입출력 갯수부터 파악하자...ㅠ

import java.util.*;
import java.io.*;

public class Main {
	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 m = Integer.parseInt(st.nextToken());
		String name[] = new String[n];
		int power[] = new int[n];
		for (int i = 0; i < n; i++) {
			st = new StringTokenizer(br.readLine());
			name[i] = st.nextToken();
			power[i] = Integer.parseInt(st.nextToken());
		}

		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		for (int i = 0; i < m; i++) {
			int characterPower = Integer.parseInt(br.readLine());

			bw.write(getName(characterPower, n, power, name) + "\n");
		}
		bw.flush();
		br.close();
	}

	private static String getName(int characterPower, int length, int[] power, String[] name) {
		int start = 0;
		int end = length - 1;
		int answer = end;
		while (start <= end) {
			int mid = (start + end) / 2;

			if (characterPower <= power[mid]) {
				answer = Math.min(mid, answer);
				end = mid - 1;
			} else {
				start = mid + 1;
			}
		}

		return name[answer];
	}
}

'알고리즘 공부 > boj' 카테고리의 다른 글

boj 20164: 홀수 홀릭 호석  (0) 2021.03.24
boj 11663: 선분 위의 점  (0) 2021.03.17
boj 2805: 나무 자르기  (0) 2021.03.16
boj 2417: 정수 제곱근  (0) 2021.03.15
boj 1789: 수들의 합  (1) 2021.03.15

상근이는 환경에 매우 관심이 많기 때문에, 나무를 필요한 만큼만 집으로 가져가려고 한다.

이때, 적어도 M미터의 나무를 집에 가져가기 위해서 절단기에 설정할 수 있는 높이의 최댓값을 구하는 프로그램을 작성하시오.

=> 최소의 최대를 구하는 문제는 뭐다?? = 이분탐색이다~~

 

import java.util.*;

public class Main {
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);

		int n = in.nextInt();
		long length = in.nextLong();
		long tree[] = new long[n];

		long start = 0;
		long end = 0;
		for (int i = 0; i < n; i++) {
			tree[i] = in.nextLong();
			end = Math.max(end, tree[i]);
		}

		long answer = 0;
		while (start <= end) {
			long mid = (start + end) / 2;
			// System.out.println(start + " " + answer + ", " + mid + " " + end);
			if (sumTree(mid, tree) >= length) {
				answer = Math.max(mid, answer);
				start = mid + 1;
			} else {
				end = mid - 1;
			}
		}
		System.out.println(answer);
	}

	private static long sumTree(long cut, long[] trees) {
		long sum = 0;
		for (long tree : trees) {
			sum += tree >= cut ? tree - cut : 0;
		}

		return sum;
	}
}

'알고리즘 공부 > boj' 카테고리의 다른 글

boj 11663: 선분 위의 점  (0) 2021.03.17
boj 19637: IF문 좀 대신 써줘  (0) 2021.03.17
boj 2417: 정수 제곱근  (0) 2021.03.15
boj 1789: 수들의 합  (1) 2021.03.15
boj 1339: 단어 수학  (0) 2021.02.14

+ Recent posts