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

 

14495번: 피보나치 비스무리한 수열

피보나치 비스무리한 수열은 f(n) = f(n-1) + f(n-3)인 수열이다. f(1) = f(2) = f(3) = 1이며 피보나치 비스무리한 수열을 나열하면 다음과 같다. 1, 1, 1, 2, 3, 4, 6, 9, 13, 19, ... 자연수 n을 입력받아 n번째 피보

www.acmicpc.net

문제

피보나치 비스무리한 수열은 f(n) = f(n-1) + f(n-3)인 수열이다. f(1) = f(2) = f(3) = 1이며 피보나치 비스무리한 수열을 나열하면 다음과 같다.

1, 1, 1, 2, 3, 4, 6, 9, 13, 19, ...

자연수 n을 입력받아 n번째 피보나치 비스무리한 수열을 구해보자!

입력

자연수 n(1 ≤ n ≤ 116)이 주어진다.

출력

n번째 피보나치 비스무리한 수를 출력한다.

예제 입력 1 복사

10

예제 출력 1 복사

19

 

문제풀이(1)

15624번 피보나치 수 7과 같은 DP 문제이다. 조건은 조금 다르다.
f(n) = f(n-1) + f(n-3) 해당 조건에 맞게 로직을 구현하면 된다.
f(1) = f(2) = f(3) = 1
또한, Int 범위를 벗어나는 경우가 있기 때문에 Bigint를 사용해야한다.

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

const dp = [BigInt(1), BigInt(1), BigInt(1)];

for (let i = 3; i < N; i++) {
  dp.push(dp[i - 1] + dp[i - 3]);
}

console.log(dp.at(-1).toString());

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

 

15624번: 피보나치 수 7

첫째 줄에 n번째 피보나치 수를 1,000,000,007으로 나눈 나머지를 출력한다.

www.acmicpc.net

문제

피보나치 수는 0과 1로 시작한다. 0번째 피보나치 수는 0이고, 1번째 피보나치 수는 1이다. 그 다음 2번째 부터는 바로 앞 두 피보나치 수의 합이 된다.

이를 식으로 써보면 Fn = Fn-1 + Fn-2 (n ≥ 2)가 된다.

n=17일때 까지 피보나치 수를 써보면 다음과 같다.

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597

n이 주어졌을 때, n번째 피보나치 수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 n이 주어진다. n은 1,000,000보다 작거나 같은 자연수 또는 0이다.

출력

첫째 줄에 n번째 피보나치 수를 1,000,000,007으로 나눈 나머지를 출력한다.

예제 입력 1 복사

10

예제 출력 1 복사

55

예제 입력 2 복사

1000

예제 출력 2 복사

517691607

 

문제풀이(1)

이전에 풀었던 1755번 숫자 놀이와 같은 DP 문제이다.

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

const dp = [0, 1];

for (let i = 2; i <= num; i++) {
  dp.push((dp[i - 2] + dp[i - 1]) % 1000000007);
}

if (num === 0 || num === 1) {
  console.log(dp[num]);
} else {
  console.log(dp.at(-1));
}

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

 

1755번: 숫자놀이

79를 영어로 읽되 숫자 단위로 하나씩 읽는다면 "seven nine"이 된다. 80은 마찬가지로 "eight zero"라고 읽는다. 79는 80보다 작지만, 영어로 숫자 하나씩 읽는다면 "eight zero"가 "seven nine"보다 사전순으로

www.acmicpc.net

문제

79를 영어로 읽되 숫자 단위로 하나씩 읽는다면 "seven nine"이 된다. 80은 마찬가지로 "eight zero"라고 읽는다. 79는 80보다 작지만, 영어로 숫자 하나씩 읽는다면 "eight zero"가 "seven nine"보다 사전순으로 먼저 온다.

문제는 정수 M, N(1 ≤ M ≤ N ≤ 99)이 주어지면 M 이상 N 이하의 정수를 숫자 하나씩 읽었을 때를 기준으로 사전순으로 정렬하여 출력하는 것이다.

입력

첫째 줄에 M과 N이 주어진다.

출력

M 이상 N 이하의 정수를 문제 조건에 맞게 정렬하여 한 줄에 10개씩 출력한다.

예제 입력 1 복사

8 28

예제 출력 1 복사

8 9 18 15 14 19 11 17 16 13
12 10 28 25 24 21 27 26 23 22
20

 

문제풀이(1)

1. 영어와 숫자가 일치하는 객체를 생성한다.
2. 최대 2자리수까지 있는 숫자들을 한글자씩 영어로 변경하는 로직을 구현한다.
3. 각 자리수를 영어를 기준으로 정렬해준다.
4. 정렬하여 맞는 숫자를 출력한다. 이때, 10개씩 끊어서 출력한다.

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

const dictionary = {
  1: "one",
  2: "two",
  3: "three",
  4: "four",
  5: "five",
  6: "six",
  7: "seven",
  8: "eight",
  9: "nine",
  0: "zero",
};

const changeResult = [];

let answer = "";

const NumberToString = (number) => {
  const str = String(number);
  const temp = [];
  temp.push(number);

  for (let i = 0; i < str.length; i++) {
    temp.push(dictionary[str[i]]);
  }

  return temp;
};

for (let i = M; i <= N; i++) {
  changeResult.push(NumberToString(i));
}

changeResult.sort((a, b) => {
  if (a[1] > b[1]) return 1;
  if (a[1] < b[1]) return -1;
  if (a[2] > b[2]) return 1;
  if (a[2] < b[2]) return -1;
});

changeResult.forEach((value, idx) => {
  answer += `${value[0]} `;
  if ((idx + 1) % 10 === 0) {
    answer.trim();
    answer += "\n";
  }
});

console.log(answer);

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

 

13699번: 점화식

다음의 점화식에 의해 정의된 수열 t(n)을 생각하자: t(0)=1 t(n)=t(0)*t(n-1)+t(1)*t(n-2)+...+t(n-1)*t(0) 이 정의에 따르면, t(1)=t(0)*t(0)=1 t(2)=t(0)*t(1)+t(1)*t(0)=2 t(3)=t(0)*t(2)+t(1)*t(1)+t(2)*t(0)=5 ... 주어진 입력 0 ≤ n

www.acmicpc.net

문제

다음의 점화식에 의해 정의된 수열 t(n)을 생각하자:

  • t(0)=1
  • t(n)=t(0)*t(n-1)+t(1)*t(n-2)+...+t(n-1)*t(0)

이 정의에 따르면,

  • t(1)=t(0)*t(0)=1
  • t(2)=t(0)*t(1)+t(1)*t(0)=2
  • t(3)=t(0)*t(2)+t(1)*t(1)+t(2)*t(0)=5
  • ...

주어진 입력 0 ≤ n ≤ 35에 대하여 t(n)을 출력하는 프로그램을 작성하시오.

입력

첫째 줄에 n (0 ≤ n ≤ 35)이 주어진다.

출력

첫째 줄에 t(n)을 출력한다.

예제 입력 1 복사

3

예제 출력 1 복사

5

예제 입력 2 복사

25

예제 출력 2 복사

4861946401452

 

문제풀이(1)

t(0)=1
t(n)=t(0)*t(n-1)+t(1)*t(n-2)+...+t(n-1)*t(0)
위의 점화식대로 문제를 풀면 되는 DP 문제이다.

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

const dp = Array.from({ length: N + 1 }, () => 0);
dp[0] = BigInt(1);
dp[1] = BigInt(1);

for (let i = 2; i <= N; i++) {
  let sum = BigInt(0);
  for (let j = 0; j < i; j++) {
    sum += BigInt(dp[j]) * BigInt(dp[i - j - 1]);
  }
  dp[i] = sum;
}
console.log(dp.at(-1).toString());

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

 

1822번: 차집합

첫째 줄에는 집합 A의 원소의 개수 n(A)와 집합 B의 원소의 개수 n(B)가 빈 칸을 사이에 두고 주어진다. (1 ≤ n(A), n(B) ≤ 500,000)이 주어진다. 둘째 줄에는 집합 A의 원소가, 셋째 줄에는 집합 B의 원소

www.acmicpc.net

문제

몇 개의 자연수로 이루어진 두 집합 A와 B가 있다. 집합 A에는 속하면서 집합 B에는 속하지 않는 모든 원소를 구하는 프로그램을 작성하시오.

입력

첫째 줄에는 집합 A의 원소의 개수 n(A)와 집합 B의 원소의 개수 n(B)가 빈 칸을 사이에 두고 주어진다. (1 ≤ n(A), n(B) ≤ 500,000)이 주어진다. 둘째 줄에는 집합 A의 원소가, 셋째 줄에는 집합 B의 원소가 빈 칸을 사이에 두고 주어진다. 하나의 집합의 원소는 2,147,483,647 이하의 자연수이며, 하나의 집합에 속하는 모든 원소의 값은 다르다.

출력

첫째 줄에 집합 A에는 속하면서 집합 B에는 속하지 않는 원소의 개수를 출력한다. 다음 줄에는 구체적인 원소를 빈 칸을 사이에 두고 증가하는 순서로 출력한다. 집합 A에는 속하면서 집합 B에는 속하지 않는 원소가 없다면 첫째 줄에 0만을 출력하면 된다.

예제 입력 1 복사

4 3
2 5 11 7
9 7 4

예제 출력 1 복사

3
2 5 11

예제 입력 2 복사

3 5
2 5 4
1 2 3 4 5

예제 출력 2 복사

0

 

문제풀이(1)

A 집합에는 속하지만 B 집합에는 속하지 않는 A 집합의 값을 찾는 문제이다.
두가지 풀이방법을 생각할 수 있다.
1. set 객체를 활용해서 집합 B를 set 객체에 할당한뒤 집합 A를 순회하며 집합 B에 존재 유무를 판단하면 된다.
2. 2진 탐색을 활용하여 집합 B에 집합 A의 값이 존재 유무를 판단하면 된다.
2진 탐색은 O(log N)의 시간복잡도를 갖지만 
set 객체를 활용한 풀이은 O(N)의 시간복잡도를 가지게 되어 이럴경우는 2진탐색보다 set 객체를 활용한 풀이가 더 좋다.

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

input.shift();

const arrA = input[0].split(" ").map(Number);
const arrB = new Set(input[1].split(" ").map(Number));

const answer = [];

arrA.forEach((num) => {
  if (!arrB.has(num)) {
    answer.push(num);
  }
});

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

console.log(answer.length === 0 ? 0 : `${answer.length}\n${answer.join(" ")}`);

 

문제풀이(2) - 2진탐색 풀이

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

input.shift();

const arrA = input[0].split(" ").map(Number);
const arrB = input[1]
  .split(" ")
  .sort((a, b) => a - b)
  .map(Number);

const answer = [];

const binarySearch = (arr, target) => {
  let low = 0;
  let high = arr.length - 1;
  let result = false;

  while (low <= high) {
    const mid = Math.floor((low + high) / 2);

    if (arr[mid] < target) {
      low = mid + 1;
    } else if (arr[mid] > target) {
      high = mid - 1;
    } else {
      result = true;
      break;
    }
  }
  return result;
};

arrA.forEach((num) => {
  if (!binarySearch(arrB, num)) {
    answer.push(num);
  }
});

console.log(answer.length === 0 ? 0 : `${answer.length}\n${answer.join(" ")}`);

 

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

 

11508번: 2+1 세일

KSG 편의점에서는 과일우유, 드링킹요구르트 등의 유제품을 '2+1 세일'하는 행사를 하고 있습니다. KSG 편의점에서 유제품 3개를 한 번에 산다면 그중에서 가장 싼 것은 무료로 지불하고 나머지 두

www.acmicpc.net

문제

KSG 편의점에서는 과일우유, 드링킹요구르트 등의 유제품을 '2+1 세일'하는 행사를 하고 있습니다. KSG 편의점에서 유제품 3개를 한 번에 산다면 그중에서 가장 싼 것은 무료로 지불하고 나머지 두 개의 제품 가격만 지불하면 됩니다. 한 번에 3개의 유제품을 사지 않는다면 할인 없이 정가를 지불해야 합니다.

예를 들어, 7개의 유제품이 있어서 각 제품의 가격이 10, 9, 4, 2, 6, 4, 3이고 재현이가 (10, 3, 2), (4, 6, 4), (9)로 총 3번에 걸쳐서 물건을 산다면 첫 번째 꾸러미에서는 13원을, 두 번째 꾸러미에서는 10원을, 세 번째 꾸러미에서는 9원을 지불해야 합니다.

재현이는 KSG 편의점에서 친구들과 같이 먹을 총 N팩의 유제품을 구입하려고 합니다. 재현이를 도와 최소비용으로 유제품을 구입할 수 있도록 도와주세요!

입력

첫 번째 줄에는 유제품의 수 N (1 ≤ N ≤ 100,000)이 주어집니다.

두 번째 줄부터 N개의 줄에는 각 유제품의 가격 Ci (1 ≤ Ci ≤ 100,000)가 주어집니다.

출력

재현이가 N개의 유제품을 모두 살 때 필요한 최소비용을 출력합니다. 정답은 231-1보다 작거나 같다.

예제 입력 1 복사

4
3
2
3
2

예제 출력 1 복사

8

예제 입력 2 복사

6
6
4
5
5
5
5

예제 출력 2 복사

21

 

문제풀이(1) - 실패(런타임 에러 (EACCES))

물건들을 3개씩 끊어서 계산을 하는데 3개일 경우에는 최소 금액 값을 뺀 나머지를 구하고,
3개 이하일 경우에는 모든 금액을 더한 값을 구한 후 모든 값을 합하면 되는 문제이다.
이때, 최소 비용을 구해야하니 내림차순으로 정렬하면 최소비용을 구할 수 있다.
1. 3번째 자리의 수만 더하지 않으면 된다.

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

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

let answer = 0;

for (let i = 0; i < N; i++) {
  if ((i + 1) % 3 !== 0) {
    answer += arr[i];
  }
}

console.log(answer);

 

문제풀이(2)

문제풀이(1)이 런타임 에러 (EACCES)가 나는 것을 확인했고, 왜 나는지 찾아본 결과 input을 다른 방식으로 해야했다.
require('fs') -> require('readline')으로 변경하면 통과되는 것을 확인할 수 있다.
이유는 fs.readFileSync와 같은 파일 입출력 함수를 사용하면, 서버에서는 해당 파일에 접근할 수 없어 에러가 발생한다고 한다.

const readline = require("readline");
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

let input = [];
rl.on("line", function (line) {
  input.push(line);
}).on("close", function () {
  const N = Number(input[0]);
  const arr = input
    .slice(1)
    .map(Number)
    .sort((a, b) => b - a);

  let answer = 0;
  for (let i = 0; i < N; i++) {
    if ((i + 1) % 3 !== 0) {
      answer += arr[i];
    }
  }

  console.log(answer);
  process.exit();
});

+ Recent posts