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

 

1758번: 알바생 강호

첫째 줄에 스타박스 앞에 서 있는 사람의 수 N이 주어진다. N은 100,000보다 작거나 같은 자연수이다. 둘째 줄부터 총 N개의 줄에 각 사람이 주려고 하는 팁이 주어진다. 팁은 100,000보다 작거나 같

www.acmicpc.net

문제

스타박스는 손님을 입장시킬 때 독특한 방법으로 입장시킨다.

스타박스에서는 손님을 8시가 될 때 까지, 문앞에 줄 세워 놓는다. 그리고 8시가 되는 순간 손님들은 모두 입구에서 커피를 하나씩 받고, 자리로 간다. 강호는 입구에서 커피를 하나씩 주는 역할을 한다.

손님들은 입구에 들어갈 때, 강호에게 팁을 준다. 손님들은 자기가 커피를 몇 번째 받는지에 따라 팁을 다른 액수로 강호에게 준다. 각 손님은 강호에게 원래 주려고 생각했던 돈 - (받은 등수 - 1) 만큼의 팁을 강호에게 준다. 만약, 위의 식으로 나온 값이 음수라면, 강호는 팁을 받을 수 없다.

예를 들어, 민호는 팁을 3원 주려고 했고, 재필이는 팁을 2원, 주현이가 팁을 1원 주려고 한 경우를 생각해보자.

민호, 재필, 주현이 순서대로 줄을 서있다면, 민호는 강호에게 3-(1-1) = 3원, 재필이는 2-(2-1) = 1원, 주현이는 1-(3-1) = -1원을 팁으로 주게 된다. 주현이는 음수이기 때문에, 강호에게 팁을 주지 않는다. 따라서, 강호는 팁을 3+1+0=4원을 받게 된다.

스타박스 앞에 있는 사람의 수 N과, 각 사람이 주려고 생각하는 팁이 주어질 때, 손님의 순서를 적절히 바꿨을 때, 강호가 받을 수 잇는 팁의 최댓값을 구하는 프로그램을 작성하시오.

입력

첫째 줄에 스타박스 앞에 서 있는 사람의 수 N이 주어진다. N은 100,000보다 작거나 같은 자연수이다. 둘째 줄부터 총 N개의 줄에 각 사람이 주려고 하는 팁이 주어진다. 팁은 100,000보다 작거나 같은 자연수이다.

출력

강호가 받을 수 있는 팁의 최댓값을 출력한다.

예제 입력 1 복사

4
3
3
3
3

예제 출력 1 복사

6

 

문제풀이(1)

문제에 로직이 있었다. 각 손님은 강호에게 원래 주려고 생각했던 돈 - (받은 등수 - 1)로 순서대로 구하면 된다.
하지만, 손님의 순서를 바꾸었을 때 줄 수 있는 최대값을 구해야하기 때문에 내림차순으로 정렬한뒤 위의 로직을 실행하면 된다.

const filePath = process.platform === "linux" ? "/dev/stdin" : "./input.txt";
const [N, ...arr] = require("fs").readFileSync(filePath).toString().trim().split("\n").map(Number);

let answer = 0;

arr.sort((a, b) => b - a);

for (let i = 0; i < N; i++) {
  const tip = arr[i] - (i + 1 - 1);
  if (tip > 0) answer += tip;
}

console.log(answer);

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

 

10157번: 자리배정

첫 줄에는 공연장의 격자 크기를 나타내는 정수 C와 R이 하나의 공백을 사이에 두고 차례대로 주어진다. 두 값의 범위는 5 ≤ C, R ≤ 1,000이다. 그 다음 줄에는 어떤 관객의 대기번호 K가 주어진다.

www.acmicpc.net

문제

어떤 공연장에는 가로로 C개, 세로로 R개의 좌석이 C×R격자형으로 배치되어 있다. 각 좌석의 번호는 해당 격자의 좌표 (x,y)로 표시된다. 

예를 들어보자. 아래 그림은 가로 7개, 세로 6개 좌석으로 구성된 7×6격자형 좌석배치를 보여주고 있다. 그림에서 각 단위 사각형은 개별 좌석을 나타내며, 그 안에 표시된 값 (x,y)는 해당 좌석의 번호를 나타낸다. 가장 왼쪽 아래의 좌석번호는 (1,1)이며, 가장 오른쪽 위 좌석의 번호는 (7,6)이다. 

(1, 6)           (7, 6)
             
      (4, 4)     (7, 4)
(1, 3)         (6, 3)  
(1, 2)            
(1, 1) (2, 1) (3, 1)       (7, 1)

이 공연장에 입장하기 위하여 많은 사람이 대기줄에 서있다. 기다리고 있는 사람들은 제일 앞에서부터 1, 2, 3, 4, . 순으로 대기번호표를 받았다. 우리는 대기번호를 가진 사람들에 대하여 (1,1)위치 좌석부터 시작하여 시계방향으로 돌아가면서 비어있는 좌석에 관객을 순서대로 배정한다. 이것을 좀 더 구체적으로 설명하면 다음과 같다.

먼저 첫 번째 사람, 즉 대기번호 1인 사람은 자리 (1,1)에 배정한다. 그 다음에는 위쪽 방향의 좌석으로 올라가면서 다음 사람들을 배정한다. 만일 더 이상 위쪽 방향으로 빈 좌석이 없으면 오른쪽으로 가면서 배정한다. 오른쪽에 더 이상 빈자리가 없으면 아래쪽으로 내려간다. 그리고 아래쪽에 더 이상 자리가 없으면 왼쪽으로 가면서 남은 빈 좌석을 배정한다. 이 후 왼쪽으로 더 이상의 빈 좌석이 없으면 다시 위쪽으로 배정하고, 이 과정을 모든 좌석이 배정될 때까지 반복한다. 

아래 그림은 7×6공연장에서 대기번호 1번부터 42번까지의 관객이 좌석에 배정된 결과를 보여주고 있다.

6 7 8 9 10 11 12
5 26 27 28 29 30 13
4 25 38 39 40 31 14
3 24 37 42 41 32 15
2 23 36 35 34 33 16
1 22 21 20 19 18 17

여러분은 공연장의 크기를 나타내는 자연수 C와 R이 주어져 있을 때, 대기 순서가 K인 관객에게 배정될 좌석 번호 (x,y)를 찾는 프로그램을 작성해야 한다. 

입력

첫 줄에는 공연장의 격자 크기를 나타내는 정수 C와 R이 하나의 공백을 사이에 두고 차례대로 주어진다. 두 값의 범위는 5 ≤ C, R ≤ 1,000이다. 그 다음 줄에는 어떤 관객의 대기번호 K가 주어진다. 단 1 ≤ K ≤ 100,000,000이다.

출력

입력으로 제시된 대기번호 K인 관객에게 배정될 좌석번호 (x,y)를 구해서 두 값, x와 y를 하나의 공백을 사이에 두고 출력해야 한다. 만일 모든 좌석이 배정되어 해당 대기번호의 관객에게 좌석을 배정할 수 없는 경우에는 0(숫자 영)을 출력해야 한다. 

예제 입력 1 복사

7 6
11

예제 출력 1 복사

6 6

 

문제풀이(1)

달팽이 모양을 만든뒤 좌표값을 구하는 문제이다.
1. C x R 크기의 2차원 배열을 0으로 채운다.
2. 문제의 달팽이 모양은 상 우 하 좌 순서로 이동한다. 이 규칙을 사용해서 달팽이를 그려준다.
3. seatNum과 target 번호가 같아졌을 때 x, y 좌표값을 출력하고 달팽이 안에 값이 없을 경우 0을 출력한다.

const filePath = process.platform === "linux" ? "/dev/stdin" : "./input.txt";
const input = require("fs").readFileSync(filePath).toString().trim().split("\n");

const [C, R] = input.shift().split(" ").map(Number);
const K = Number(input[0]);

// 0으로 채워진 2차원 배열 생성
const arr = Array.from({ length: R }, () => Array.from({ length: C }, () => 0));

const moves = [
  [-1, 0],
  [0, 1],
  [1, 0],
  [0, -1],
];

let x = 0;
let y = R - 1;
let seatNum = 1;
let direction = 0;

while (seatNum <= C * R) {
  arr[y][x] = seatNum;

  // 좌석번호랑 대기번호가 같을 경우
  if (seatNum === K) break;

  seatNum++;
  const nx = x + moves[direction][1];
  const ny = y + moves[direction][0];

  if (nx < 0 || ny < 0 || nx >= C || ny >= R || arr[ny][nx] !== 0) {
    // 상 -> 우 -> 하 -> 좌 순서로 달팽이가 이동
    direction = (direction + 1) % 4;
  }

  x += moves[direction][1];
  y += moves[direction][0];
}

console.log(seatNum !== K ? 0 : `${x + 1} ${R - y}`);

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

 

5568번: 카드 놓기

예제 1의 경우 상근이는 11, 12, 21, 112, 121, 122, 212를 만들 수 있다.

www.acmicpc.net

문제

상근이는 카드 n(4 ≤ n ≤ 10)장을 바닥에 나란히 놓고 놀고있다. 각 카드에는 1이상 99이하의 정수가 적혀져 있다. 상근이는 이 카드 중에서 k(2 ≤ k ≤ 4)장을 선택하고, 가로로 나란히 정수를 만들기로 했다. 상근이가 만들 수 있는 정수는 모두 몇 가지일까?

예를 들어, 카드가 5장 있고, 카드에 쓰여 있는 수가 1, 2, 3, 13, 21라고 하자. 여기서 3장을 선택해서 정수를 만들려고 한다. 2, 1, 13을 순서대로 나열하면 정수 2113을 만들 수 있다. 또, 21, 1, 3을 순서대로 나열하면 2113을 만들 수 있다. 이렇게 한 정수를 만드는 조합이 여러 가지 일 수 있다.

n장의 카드에 적힌 숫자가 주어졌을 때, 그 중에서 k개를 선택해서 만들 수 있는 정수의 개수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 n이, 둘째 줄에 k가 주어진다. 셋째 줄부터 n개 줄에는 카드에 적혀있는 수가 주어진다.

출력

첫째 줄에 상근이가 만들 수 있는 정수의 개수를 출력한다.

예제 입력 1 복사

4
2
1
2
12
1

예제 출력 1 복사

7

 

문제풀이(1)

n개의 카드중에서 k개의 카드만 나열하여 만들 수 있는 중복이 제거된 정수들의 수를 구하는 순열, 조합 문제이다.
중복을 제거하기 위해 set을 사용한다.
dfs로 탐색한다.

const filePath = process.platform === "linux" ? "/dev/stdin" : "./input.txt";
const [n, k, ...cards] = require("fs").readFileSync(filePath).toString().trim().split("\n").map(Number);

const combinations = new Set();
const selectedCards = [];
const visitedCards = new Array(n).fill(false);

findDistinctCombinations(selectedCards, visitedCards);

console.log(combinations.size);

function findDistinctCombinations(selected, visited) {
  // 선택된 카드의 개수가 k랑 같을 경우 조합에 추가
  if (selected.length === k) {
    combinations.add(selected.join(""));
    return;
  }

  for (let i = 0; i < cards.length; i++) {
    // 선택되지 않은 카드들의 조합을 찾기위함
    if (!visited[i]) {
      visited[i] = true;
      selected.push(cards[i]); // 선택된 카드에 추가
      findDistinctCombinations(selected, visited); // 재귀
      visited[i] = false;
      selected.pop();
    }
  }
}

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

 

2670번: 연속부분최대곱

첫째 줄은 나열된 양의 실수들의 개수 N이 주어지고, 그 다음 줄부터 N개의 수가 한 줄에 하나씩 들어 있다. N은 10,000 이하의 자연수이다. 실수는 소수점 첫째자리까지 주어지며, 0.0보다 크거나

www.acmicpc.net

 

문제

N개의 실수가 있을 때, 한 개 이상의 연속된 수들의 곱이 최대가 되는 부분을 찾아, 그 곱을 출력하는 프로그램을 작성하시오. 예를 들어 아래와 같이 8개의 양의 실수가 주어진다면,

색칠된 부분의 곱이 최대가 되며, 그 값은 1.638이다.

입력

첫째 줄은 나열된 양의 실수들의 개수 N이 주어지고, 그 다음 줄부터 N개의 수가 한 줄에 하나씩 들어 있다. N은 10,000 이하의 자연수이다. 실수는 소수점 첫째자리까지 주어지며, 0.0보다 크거나 같고, 9.9보다 작거나 같다.

출력

계산된 최댓값을 소수점 이하 넷째 자리에서 반올림하여 소수점 이하 셋째 자리까지 출력한다.

예제 입력 1 복사

8
1.1
0.7
1.3
0.9
1.4
0.8
0.7
1.4

예제 출력 1 복사

1.638

 

문제풀이(1)

첫 번째 값을 temp에 추가한뒤 이후 나오는 연속된 값을 곱한 값과 현재의 값을 비교하여 계산한다.

const filePath = process.platform === "linux" ? "/dev/stdin" : "./input.txt";
const input = require("fs").readFileSync(filePath).toString().trim().split("\n").map(Number);

const N = input.shift();
let temp = input[0];

let answer = 0;

for (let i = 1; i < N; i++) {
  // 현재 숫자가 이전값 *  현재 숫자보다 클 경우 이전값을 현재 값으로 변경한다.
  if (input[i] > temp * input[i]) {
    temp = input[i];
  } else {
    temp *= input[i];
  }
  answer = Math.max(temp, answer);
}

console.log(answer.toFixed(3));

 

문제풀이(2) - 리팩토링

temp 대신 currentProduct를 사용하여 현재까지의 곱을 나타내고, answer 대신 maxProduct를 사용하여 최대 곱을 나타냄
또한, 각 숫자에 대해 수행하는 작업을 한 줄로 줄임.

const filePath = process.platform === "linux" ? "/dev/stdin" : "./input.txt";
const input = require("fs").readFileSync(filePath).toString().trim().split("\n").map(Number);

const N = input.shift();
let maxProduct = input[0];

let currentProduct = maxProduct;

for (let i = 1; i < N; i++) {
  const currentNumber = input[i];
  currentProduct = currentNumber > currentProduct * currentNumber ? currentNumber : currentProduct * currentNumber;
  maxProduct = Math.max(currentProduct, maxProduct);
}

console.log(maxProduct.toFixed(3));

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

 

9507번: Generations of Tribbles

꿍은 군대에서 진짜 할짓이 없다. 그래서 꿍만의 피보나치를 만들어보려고 한다. 기존의 피보나치는 너무 단순해서 꿍은 좀더 복잡한 피보나치를 만들어보고자 한다. 그래서 다음과 같은 피보

www.acmicpc.net

문제

꿍은 군대에서 진짜 할짓이 없다. 그래서 꿍만의 피보나치를 만들어보려고 한다. 기존의 피보나치는 너무 단순해서 꿍은 좀더 복잡한 피보나치를 만들어보고자 한다. 그래서 다음과 같은 피보나치를 만들었다. 꿍만의 피보나치 함수가 koong(n)이라고 할 때,

n < 2 :                         1
n = 2 :                         2
n = 3 :                         4
n > 3 : koong(n − 1) + koong(n − 2) + koong(n − 3) + koong(n − 4)

이다.

여러분도 꿍 피보나치를 구해보아라.

입력

입력의 첫 번째 줄을 테스트 케이스의 개수 t (0 < t < 69)가 주어진다. 다음 t줄에는 몇 번째 피보나치를 구해야하는지를 나타내는 n(0 ≤ n ≤ 67)이 주어진다.

출력

각 테스트 케이스에 대해, 각 줄에 꿍 피보나치값을 출력하라.

예제 입력 1 복사

8
0
1
2
3
4
5
30
67

예제 출력 1 복사

1
1
2
4
8
15
201061985
7057305768232953720

 

문제풀이(1)

변형된 피보나치수를 구하면되는 문제이다.
koong(n − 1) + koong(n − 2) + koong(n − 3) + koong(n − 4)
기본적으로 주어지는 수는 1, 1, 2, 4이다.

주어지는 수의 범위가 int를 넘어가기 때문에 Bigint를 사용한다.

const filePath = process.platform === "linux" ? "/dev/stdin" : "./input.txt";
const input = require("fs").readFileSync(filePath).toString().trim().split("\n").map(Number);

const N = input.shift();
const answer = [];

for (let i = 0; i < N; i++) {
  const dp = [1, 1, 2, 4];

  for (let j = 4; j < input[i] + 1; j++) {
    const num = BigInt(dp[j - 1]) + BigInt(dp[j - 2]) + BigInt(dp[j - 3]) + BigInt(dp[j - 4]);
    dp.push(num.toString());
  }
  answer.push(dp[input[i]]);
}

console.log(answer.join("\n"));

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

 

25192번: 인사성 밝은 곰곰이

첫번째 새로운 사람이 들어온 뒤  pjshwa, chansol, chogahui05은 모두 곰곰티콘으로 인사했다. 두번째 새로운 사람이 들어온 뒤  pjshwa와 chansol은 다시 곰곰티콘으로 인사했다.

www.acmicpc.net

문제

알고리즘 입문방 오픈 채팅방에서는 새로운 분들이 입장을 할 때마다 곰곰티콘을 사용해 인사를 한다. 이를 본 문자열 킬러 임스는 채팅방의 기록을 수집해 그 중 곰곰티콘이 사용된 횟수를 구해 보기로 했다.

ENTER는 새로운 사람이 채팅방에 입장했음을 나타낸다. 그 외는 채팅을 입력한 유저의 닉네임을 나타낸다. 닉네임은 숫자 또는 영문 대소문자로 구성되어 있다.

새로운 사람이 입장한 이후 처음 채팅을 입력하는 사람은 반드시 곰곰티콘으로 인사를 한다. 그 외의 기록은 곰곰티콘을 쓰지 않은 평범한 채팅 기록이다.

채팅 기록 중 곰곰티콘이 사용된 횟수를 구해보자!

입력

첫 번째 줄에는 채팅방의 기록 수를 나타내는 정수  이 주어진다. (1≤N≤100000)

두 번째 줄부터  개의 줄에 걸쳐 새로운 사람의 입장을 나타내는 ENTER, 혹은 채팅을 입력한 유저의 닉네임이 문자열로 주어진다. (문자열길이1≤문자열 길이≤20)

첫 번째 주어지는 문자열은 무조건 ENTER이다.

출력

채팅 기록 중 곰곰티콘이 사용된 횟수를 출력하시오.

예제 입력 1 복사

9
ENTER
pjshwa
chansol
chogahui05
lms0806
pichulia
r4pidstart
swoon
tony9402

예제 출력 1 복사

8

 

문제풀이(1)

ENTER : 새로운 사람이 채팅방에 입장했음.
그 외 : 채팅을 입력한 유저의 닉네임
ENTER로 새로운 사람이 채팅방에 입장했다는 커맨드 다음으로 나온 닉네임의 개수를 구한다.
ENTER는 여러번 나올수 있고, 한 번의 ENTER에는 중복된 닉네임이 없어야하며 다른 ENTER에는 이전 ENTER와 중복된 닉네임이 있을 수 있다.
set을 이용해서 중복제거를 하고 ENTER가 나올때마다 set을 초기화 해주면 된다.

const filePath = process.platform === "linux" ? "/dev/stdin" : "./input.txt";
const input = require("fs").readFileSync(filePath).toString().trim().split("\n");

const N = Number(input.shift());

const set = new Set();
let answer = 0;

for (let i = 0; i < N; i++) {
  if (input[i] === "ENTER") {
    answer += set.size;
    set.clear();
    continue;
  }

  set.add(input[i]);
  if (i === N - 1) {
    answer += set.size;
  }
}

console.log(answer);

+ Recent posts