CSS background

1
2
3
4
5
6
background-color
background-image
background-repeat
background-attachment
background-position
background (shorthand property)

background-color

컬러는 다음 3가지 값만 가능하다.

  1. 유효한 컬러이름 ex) ‘red’, ‘green’ …
  2. HEX 값 ex) ‘#ff0000’
  3. RGB 값 ex) ‘rgb(255,0,0)’
1
2
3
4
5
6
7
8
div {
background-color: green;
opacity: 0.3;
}

div {
background: rgba(0, 128, 0, 0.3); /* Green background with 30% opacity */
}

opacity 속성을 줘서 배경을 흐리게 할 수 있다.

❗️opacity 속성을 사용하게 될 경우 자식 요소까지 흐려지므로 가독성이 떨어질 수도 있다.

background-image

기본값으로 image는 반복되어서 전체 요소를 덮어준다.

신기한 것은 p 태그에도 해당 속성을 설정할 수 있다는 점이다.

1
2
3
p {
background-image: url("paper.gif");
}

repeat, position 속성

image를 가로, 세로 반복되게 설정하는 속성이다.

position은 요소내에서 image의 위치를 설정한다.

1
2
3
4
5
body {
background-image: url("img_tree.png");
background-repeat: no-repeat;
background-position: bottom;
}

해당 배경 이미지를 아래에 위치시킨다.

background-attachment

1
2
3
4
5
6
body {
background-image: url("img_tree.png");
background-repeat: no-repeat;
background-position: right top;
background-attachment: fixed;
}

fixed로 설정하면 position fixed 처럼 배경이미지가 스크롤 하여도 해당 위치에 고정되어 있다.

scroll로 설정하면 다른 페이지를 보려고 스크롤 할 때, 배경도 스크롤된다.

단축표현

1
2
3
body {
background: #ffffff url("img_tree.png") no-repeat right top;
}

한줄로 쓸 수 있는데, 순서는 다음과 같다.

  • background-color
  • background-image
  • background-repeat
  • background-attachment
  • background-position

댓글 공유

netlify 배포하기

🖱 1. 드래그 앤 드랍으로 배포하기

  1. npm run build 명령어를 실행하여 build 파일을 만든다.
  2. netlify 홈페이지에 가서 build 폴더를 드래그 드랍한다.

netlify사이트

배포 끝!

🔗 Cocktail project site Link

❗️React Router 사용하여 netlify 배포시 문제

React Router를 사용하여 netlify에 배포했을 때, root 경로이외의 직접적으로 경로에 접근할 때, Page Not Found가 뜨는 문제가 있다.

📌 문제 발생 원인!

해당 문제는 React Router는 클라이언트 사이드에서 라우팅을 다루기때문에, root 페이지가 아닌 경로로 직접적으로 방문했을 경우, netliffy는 해당 경로를 어떻게 다룰지 알 수 없다.

🙆🏻‍♂️ 어떻게 해결하는가?

netlify에서 _redirects 파일을 제공한다. 여기에 netlify가 클라이언트 사이드에서 다루지 않는 URL을 어떻게 다룰 지에 대한 코드를 적어주면 된다.

1
2
// _redirects 파일
/* /index.html 200

폴더구조

SPA 프레임워크를 사용하여 애플리케이션을 만들고 history pushstate를 사용하여 URL을 클린하게 사용하는 경우 위와 같이 파일을 생성하여 적어주면된다.

이렇게 하면 어떤 URL로 브라우저 요청이 오던지 간에 404 대신 index.html을 제공한다.

2. github에서 CI 사용하여 배포하기

이 방법을 사용하면 프로젝트 변경사항을 반영하여 배포하기 편리하다.

  1. 깃헙 레포를 생성한다.
  2. 이미 존재하는 파일을 깃헙 레포에 푸시한다.
1
2
3
4
5
6
git init
git add .
git commit -m "initial commit"
git remote add origin https://github.com/loco9939/react-cocktail-project.git
git branch -M main
git push -u origin main
  1. netlify에 가서 “add new site” 버튼 클릭한 후 github으로 배포하기 하여 생성한 레포를 선택하고 배포한다.

netlify사이트

  1. package.json에 가서 build 명령어를 수정해주자.
1
2
3
4
5
6
7
8
// package.json
{
"scripts": {
...
"build": "CI= react-scripts build",
...
}
}

보통 react-scripts build만 되어있을텐데 앞에 CI= 을 추가해주자.

  1. 이후 해당 개발 파일을 수정한다음 깃헙에 push 하게 되면 netlify 가 알아서 배포를 해준다.

body 태그의 배경 색깔을 변경해보았다.

색깔변경후화면

댓글 공유

문제

수열 A가 주어졌을 때, 그 수열의 증가 부분 수열 중에서 합이 가장 큰 것을 구하는 프로그램을 작성하시오.

예를 들어, 수열 A = {1, 100, 2, 50, 60, 3, 5, 6, 7, 8} 인 경우에 합이 가장 큰 증가 부분 수열은 A = {1, 100, 2, 50, 60, 3, 5, 6, 7, 8} 이고, 합은 113이다.

입력

첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000)이 주어진다.

둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (1 ≤ Ai ≤ 1,000)

출력

첫째 줄에 수열 A의 합이 가장 큰 증가 부분 수열의 합을 출력한다.

예제 입력 1

1
2
10
1 100 2 50 60 3 5 6 7 8

예제 출력 1

1
113

내 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const [N, input] = require("fs")
.readFileSync("/dev/stdin")
.toString()
.trim()
.split("\n");
const A = input.split(" ").map(Number);

function maxIncreasingSubArray(A) {
const n = A.length;
const DP = [...A];

for (let i = 1; i < n; i++) {
for (let j = 0; j < i; j++) {
if (A[i] > A[j] && DP[i] < DP[j] + A[i]) {
DP[i] = DP[j] + A[i];
}
}
}
return Math.max(...DP);
}

console.log(maxIncreasingSubArray(A));

풀이

  1. DP는 해당 인덱스까지 가장 긴 부분수열의 합을 나타낸다. 이를 계산하기 편하게 하기 위해 DP에 A 수열의 값을 spread 문법으로 복사해준다.

  2. 어짜피 DP[0]은 1로 확정이므로 i(인덱스)가 1부터 반복문을 순회한다.
    이는 DP에 값을 저장하기 위한 반복문이다.

  3. i 이전까지 수열 값과 A[i]값을 비교하여 A[i]가 A[j]보다 크고 DP[i] 값이 DP[j]+A[i] 보다 작으면 증가하는 부분 수열에 포함될 수 있다.

그렇기 때문에 해당 DP[i]값을 새로운 값으로 갱신해준다.

예시

1
const A = [1, 100, 2, 50, 60, 3, 5, 6, 7, 8];

1. i = 1 && j = 0 일 때

  • A[1] = 100, A[0] = 1이므로 A[i] > A[j] 조건 만족한다
  • DP[1] < DP[0] + A[1] 만족하므로 DP[1] = DP[0] + A[1]로 갱신
1
DP = [1, 101, 2, 50, 60, 3, 5, 6, 7, 8];

2. i = 2 이고

2.1. j = 0 일 때

  • A[2]=2, A[0] = 1 이므로 A[i] > A[j] 조건 만족한다.
  • DP[2] < DP[0] + A[2] 만족하므로 DP[2] = DP[0] + A[2]로 갱신

2.2. j = 1 일 때,

  • A[2]=2, A[1] = 100 이므로 A[i] > A[j] 조건 만족하지 못한다.
1
DP = [1, 101, 3, 50, 60, 3, 5, 6, 7, 8];

즉, 0번째부터 해당 인덱스까지 수열의 두 수를 비교하고 DP에 저장된 값도 비교하여 둘다 만족하면 DP 값을 갱신하는 것이다.

댓글 공유

공부 목표

<오늘부터 CSS 마스터> 챕터를 시작하게 된 이유는 평소 리액트로 상태관리에 대해서만 생각하다보니 CSS로 화면을 스타일링 하는 것이 쉽게 나오지 않게 되었다.

그래서 이를 개선하고자 매일 CSS 공부를 한개씩 익혀가도록 목표를 세웠습니다!

공부는 W3Cschool) 사이트를 참조하면서 공부를 하거나 Youtube 강의를 보고 배울 수 도 있으며, 간단한 웹 사이트 스타일링을 클론해보는 방향으로 진행할 것입니다.

CSS란?

  • CSS는 Cascading Style sheet를 의미한다.

말 그대로 폭포처럼 떨어져 내리는 스타일시트이다.

  • CSS는 HTML 요소가 화면에 어떻게 나타날지를 묘사한다.

CSS를 왜 사용하나요?

CSS는 디자인, 레이아웃, 변화등을 포함한 웹 페이지의 스타일을 다른 기기와 화면 크기에 따라 정의하기 위해 사용한다.

CSS는 큰 문제를 해결한다!

HTML은 웹 페이지를 구성하기 위해 태그를 포함하도록 의도된 적이 없다!

나 색상 속성이 HTML 3.2에 추가되었을 때, 모든 페이지에 글꼴과 색상을 추가하는 것은 매우 비용이 많이 드는 작업이 되었다.

그래서 W3C가 CSS를 만들어 냈고 HTML 페이지에서 스타일 형식을 제거하였다.

CSS 문법

CSS 문법

CSS 선택자

CSS 선택자는 스타일링하고 싶은 HTML 요소를 선택한다.

총 5가지의 항목이 있다.

  1. 간단한 선택자
    • name, id, class 기반으로 요소 선택하기
  2. 조합 선택자
    • 둘 사이의 특정한 관계를 기반으로 요소 선택하기
  3. Pseudo-class 선택자
    • 특정 상태를 기반으로 요소 선택하기
  4. Pseudo-element 선택자
    • 요소의 일부분을 스타일링하고 선택하기
  5. Attribute 선택자
    • attribute나 attribute 값을 기반으로 요소 선택하기

center class를 포함한 p태그 선택자

1
2
3
4
p.center {
text-align: center;
color: red;
}

❗️ p태그와 .center 사이에 띄어쓰기가 있으면 안된다!

* 전체 선택자

1
2
3
4
* {
text-align: center;
color: blue;
}

Group 선택자

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
h1 {
text-align: center;
color: red;
}

p {
text-align: center;
color: red;
}

/* 같은 스타일이라면 쉼표로 구분하여 한줄로 작성 가능 */
h1,
p {
text-align: center;
color: red;
}

CSS 추가하는 방법 3가지

  1. 외부 CSS
  2. 내부 CSS
  3. inline CSS

다중 CSS 우선순위

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="mystyle.css" />
<style>
h1 {
color: orange;
}
</style>
</head>
</html>

만약 mystyle.css에서 h1을 blue로 하였더라도 CSS는 가장 나중에 읽은 CSS를 적용하기 때문에 h1의 color는 orange가 될 것이다.

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html>
<head>
<style>
h1 {
color: orange;
}
</style>
<link rel="stylesheet" type="text/css" href="mystyle.css" />
</head>
</html>

만약 mystyle.css가 더 아래에 있어서 나중에 읽힌다면 h1은 mystyle.css에서 정의한 스타일로 적용될 것이다.

Cascading 우선순위

  1. inline style
  2. 태그에 있는 외부 CSS와 내부 CSS
  3. 브라우저 기본

댓글 공유

문제

0부터 N까지의 정수 K개를 더해서 그 합이 N이 되는 경우의 수를 구하는 프로그램을 작성하시오.

덧셈의 순서가 바뀐 경우는 다른 경우로 센다(1+2와 2+1은 서로 다른 경우). 또한 한 개의 수를 여러 번 쓸 수도 있다.

입력

첫째 줄에 두 정수 N(1 ≤ N ≤ 200), K(1 ≤ K ≤ 200)가 주어진다.

출력

첫째 줄에 답을 1,000,000,000으로 나눈 나머지를 출력한다.

예제

예제 입력 1

1
2
20 2

예제 출력 1

1
2
21

예제 입력 2

1
2
6 4

예제 출력 2

1
84

내 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const [N, K] = require("fs")
.readFileSync("/dev/stdin")
.toString()
.trim()
.split(" ")
.map(Number);

const DP = Array.from({ length: N + 1 }, (_, i) => {
if (i === 1) return Array.from({ length: K + 1 }, (_, i) => i + 1);
return new Array(K + 1).fill(1);
});

for (let i = 2; i <= N; i++) {
for (let j = 1; j <= K; j++) {
DP[i][j] = (DP[i - 1][j] + DP[i][j - 1]) % 1000000000;
}
}

console.log(DP[N][K - 1]);
  • ✏️ N = 1인 경우 K = 1,2,3 …200 경우의 수를 생각해보았다.
    • ❗️ 1개의 수로 1을 만들 수 있는 경우의 수는 1가지이다.
    • 2개의 수로 1을 만들 수 있는 경우의 수는 0+1, 1+0으로 2가지이다.
    • 3개의 수로 1을 만들 수 있는 경우의 수는 0+0+1, 0+1+0, 1+0+0으로 3가지이다…
  • N = 2인 경우 K = 1,2,3 …200 경우의 수를 생각해보았다.
    • ❗️ 1개의 수로 2를 만들 수 있는 경우의 수는 1가지이다.
    • 2개의 수로 2를 만들 수 있는 경우의 수는 1+1, 2+0, 0+2로 3가지이다.
    • 3개의 수로 2를 만들 수 있는 경우의 수는 1+1+0, 1+0+1, 0+1+1, 2+0+0, 0+2+0, 0+0+2로 6가지이다…

❗️의 조건을 가지고 DP[N][k] 2차원 배열에서, DP[N][1] = 1인 것을 알 수 있다.

✏️의 조건을 가지고 DP[1][k] = K 인 것을 알 수 있다.

Frame.png

위와 같은 점화식을 발견하였고 그에 알맞은 식을 만들었다.

댓글 공유

문제

정수 4를 1, 2, 3의 합으로 나타내는 방법은 총 7가지가 있다. 합을 나타낼 때는 수를 1개 이상 사용해야 한다.

  • 1+1+1+1
  • 1+1+2
  • 1+2+1
  • 2+1+1
  • 2+2
  • 1+3
  • 3+1

정수 n이 주어졌을 때, n을 1, 2, 3의 합으로 나타내는 방법의 수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스는 한 줄로 이루어져 있고, 정수 n이 주어진다. n은 양수이며 1,000,000보다 작거나 같다.

출력

각 테스트 케이스마다, n을 1, 2, 3의 합으로 나타내는 방법의 수를 1,000,000,009로 나눈 나머지를 출력한다.

예제

예제 입력 1

1
2
3
4
5
3
4
7
10

예제 출력 1

1
2
3
7
44
274

내 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const input = require("fs")
.readFileSync("/dev/stdin")
.toString()
.trim()
.split("\n")
.map(Number);
const N = input.shift();

const DP = [0, 1, 2, 4];

input.forEach((num) => {
for (let i = 4; i <= num; i++) {
DP[i] = (DP[i - 3] + DP[i - 2] + DP[i - 1]) % 1000000009;
}
console.log(DP[num]);
});
  • 1을 1,2,3으로 만들 수 있는 경우의 수, 2를 1,2,3으로 만들 수 있는 경우의 수, 3을 1,2,3으로 만들 수 있는 경우의 수는 직접 구할 수 있어서 구하였다.
  • 4부터는 맨 마지막에 1,2,3이 오는 경우의 수를 나누어서 생각하였다.
    • 맨 마지막에 1이 오는 경우 ⇒ 1+1+1+1, 1+2+1, 2+1+1, 3+1 ⇒ DP[4-1]
    • 맨 마지막에 2가 오는 경우 ⇒ 1+1+2, 2+2 ⇒ DP[4-2]
    • 맨 마지막에 3이 오는 경우 ⇒ 1+3 ⇒ DP[4-3]

하지만 위와 같은 방법으로 하게되면 n이 1,000,000이 주어졌을 때, 반복문은 n-3회 진행하므로 시간초과가 난다. 심지어 테스트 케이스 수가 T개 주어지는 만큼 n-3회 반복해야 하므로 매우 오래걸릴 수도 있게된다.

즉, input 값 중에서 가장 큰 값으로 반복문 한번만 순회한 다음, 완성된 DP 배열에서 해당 값을 찾는 식으로 방법을 바꿨다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const input = require("fs")
.readFileSync("/dev/stdin")
.toString()
.trim()
.split("\n")
.map(Number);
const N = input.shift();

function solution(n, arr) {
if (n < 4) return arr[n - 1];

for (let i = 4; i <= n; i++) {
DP[i] = (DP[i - 3] + DP[i - 2] + DP[i - 1]) % 1000000009;
}
return arr;
}

const DP = [0, 1, 2, 4];
solution(Math.max(...input), DP);

input.forEach((num) => {
console.log(DP[num]);
});

댓글 공유

문제

RGB거리에는 집이 N개 있다. 거리는 선분으로 나타낼 수 있고, 1번 집부터 N번 집이 순서대로 있다.

집은 빨강, 초록, 파랑 중 하나의 색으로 칠해야 한다. 각각의 집을 빨강, 초록, 파랑으로 칠하는 비용이 주어졌을 때, 아래 규칙을 만족하면서 모든 집을 칠하는 비용의 최솟값을 구해보자.

  • 1번 집의 색은 2번 집의 색과 같지 않아야 한다.
  • N번 집의 색은 N-1번 집의 색과 같지 않아야 한다.
  • i(2 ≤ i ≤ N-1)번 집의 색은 i-1번, i+1번 집의 색과 같지 않아야 한다.

입력

첫째 줄에 집의 수 N(2 ≤ N ≤ 1,000)이 주어진다. 둘째 줄부터 N개의 줄에는 각 집을 빨강, 초록, 파랑으로 칠하는 비용이 1번 집부터 한 줄에 하나씩 주어진다. 집을 칠하는 비용은 1,000보다 작거나 같은 자연수이다.

출력

첫째 줄에 모든 집을 칠하는 비용의 최솟값을 출력한다.

예제

예제 입력 1

1
2
3
4
5
3
26 40 83
49 60 57
13 89 99

예제 출력 1

1
2
96

예제 입력 2

1
2
3
4
5
3
1 100 100
100 1 100
100 100 1

예제 출력 2

1
2
3

예제 입력 3

1
2
3
4
5
3
1 100 100
100 100 100
1 100 100

예제 출력 3

1
2
102

예제 입력 4

1
2
3
4
5
6
7
8
6
30 19 5
64 77 64
15 19 97
4 71 57
90 86 84
93 32 91

예제 출력 4

1
2
208

예제 입력 5

1
2
3
4
5
6
7
8
9
10
8
71 39 44
32 83 55
51 37 63
89 29 100
83 58 11
65 13 15
47 25 29
60 66 19

예제 출력 5

1
253

내 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const [N, ...arr] = require("fs")
.readFileSync("/dev/stdin")
.toString()
.trim()
.split("\n");
const input = arr.map((houseCosts) => houseCosts.split(" ").map(Number));

function solution(n, rgb) {
const DP = Array.from({ length: n + 1 }, () => new Array(3).fill(0));
DP[1] = rgb[0];
for (let i = 2; i <= n; i++) {
DP[i][0] = Math.min(DP[i - 1][1], DP[i - 1][2]) + rgb[i - 1][0];
DP[i][1] = Math.min(DP[i - 1][0], DP[i - 1][2]) + rgb[i - 1][1];
DP[i][2] = Math.min(DP[i - 1][1], DP[i - 1][0]) + rgb[i - 1][2];
}
console.log(Math.min(...DP[n]));
}

solution(+N, input);
  • 처음에는 1번째 집이 R,G,B를 선택하는 경우의 수를 구하고 이를 이 중 가장 작은 것을 가지고 다음 집을 구한다고 생각했다. 생각은 했는데 이를 코드로 어떻게 짜야할지 생각을 못해서 경우의수를 일일히 적어보고 패턴을 찾아보려고 했다.
  • 하지만 못찾아서 다른 사람의 해설을 참고하였다. 문제가 복잡해보이지만 단순하게 생각하면 인접한 집끼리는 같은 색상을 가질 수 없다는 것이 전부이다.

우선, DP 배열을 만들고 해당 DP[i][0]은 i번째 집을 Red로 색칠하는 비용을 저장한다.

  • DP[1] = input[0] 이 성립한다.
  • 이후 i = 2 부터 반복문을 진행한다.
    1. DP[2]가 R로 색칠될 경우의 비용을 저장한다. ⇒ DP[2]가 R 이기 위해서는 DP[1]에서 G, B로 색칠되어야만 가능하다. 즉 DP[1]에서 G, B를 칠하는 비용 중 최소값을 구하고 이에 input의 2번째 집에 해당하는 비용 중 R을 색칠하는 비용을 더해주면 DP[2][0] 즉, 2번째 집을 R로 칠할 때 최소 비용을 구할 수 있다.
    2. DP[2][1]은 이전 집에서 R, B 중 최소값에다가 input의 2번째 집에 해당하는 비용 중 G을 색칠하는 비용을 더해주면 DP[2][1]의 최솟값을 구할 수 있다.

댓글 공유

문제

어떤 동물원에 가로로 두칸 세로로 N칸인 아래와 같은 우리가 있다.

https://www.acmicpc.net/upload/201004/dnfl.JPG

이 동물원에는 사자들이 살고 있는데 사자들을 우리에 가둘 때, 가로로도 세로로도 붙어 있게 배치할 수는 없다. 이 동물원 조련사는 사자들의 배치 문제 때문에 골머리를 앓고 있다.

동물원 조련사의 머리가 아프지 않도록 우리가 2*N 배열에 사자를 배치하는 경우의 수가 몇 가지인지를 알아내는 프로그램을 작성해 주도록 하자. 사자를 한 마리도 배치하지 않는 경우도 하나의 경우의 수로 친다고 가정한다.

입력

첫째 줄에 우리의 크기 N(1≤N≤100,000)이 주어진다.

출력

첫째 줄에 사자를 배치하는 경우의 수를 9901로 나눈 나머지를 출력하여라.

예제

예제 입력 1

1
4

예제 출력 1

1
41

내 코드

해설사진

N = 3 까지의 경우의 수를 적고나서 점화식을 생각해보았다. 처음에는 DP[i] = 2*DP[i-1] + (2**(i-1) - 1) 이라고 생각했는데 오답이였다.

다시 점화식을 세웠다.

1
DP[i] = 2 * DP[i - 1] + DP[i - 2];
1
2
3
4
5
6
7
8
9
const input = +require("fs").readFileSync("/dev/stdin").toString().trim();

const DP = [0, 3, 7, 17];

for (let i = 4; i <= input; i++) {
DP[i] = (2 * DP[i - 1] + DP[i - 2]) % 9901;
}

console.log(DP[input]);

위 처럼 직접 경우의 수를 다 계산할 수 있었지만, DP를 2차원 배열로 설정하고 첫번째 칸에 공백이 오는경우, 좌측에 사자 채우는 경우, 우측에 사자 채우는 경우를 나눠서 구해볼 수 도 있을 것 같다.

댓글 공유

문제

오르막 수는 수의 자리가 오름차순을 이루는 수를 말한다. 이때, 인접한 수가 같아도 오름차순으로 친다.

예를 들어, 2234와 3678, 11119는 오르막 수이지만, 2232, 3676, 91111은 오르막 수가 아니다.

수의 길이 N이 주어졌을 때, 오르막 수의 개수를 구하는 프로그램을 작성하시오. 수는 0으로 시작할 수 있다.

입력

첫째 줄에 N (1 ≤ N ≤ 1,000)이 주어진다.

출력

첫째 줄에 길이가 N인 오르막 수의 개수를 10,007로 나눈 나머지를 출력한다.

예제

예제 입력 1

1
1

예제 출력 1

1
10

예제 입력 2

1
2

예제 출력 2

1
55

예제 입력 3

1
3

예제 출력 3

1
220

내 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const length = +require("fs").readFileSync("/dev/stdin").toString().trim();

function Sum(arr) {
return arr.reduce((acc, cur) => acc + cur, 0);
}

const DP = Array.from({ length: length + 1 }, (_, i) => {
if (i === 1) return new Array(10).fill(1);
if (i === 2) return Array.from({ length: 10 }, (_, i) => 10 - i);
return Array(10).fill(0);
});

for (let i = 3; i <= length; i++) {
for (let j = 0; j <= 9; j++) {
for (let k = j; k <= 9; k++) {
DP[i][j] += DP[i - 1][k] % 10007;
}
}
}

console.log(Sum(DP[length]) % 10007);
  • 길이가 i이고, j로 시작하는 수로 오름차순을 만들 수 있는 경우의 수를 DP 배열에 저장하였다.
1
2
// 점화식
DP[i][j] = DP[i-1]의 j~9까지의 합

댓글 공유

문제

상근이의 여동생 상냥이는 문방구에서 스티커 2n개를 구매했다. 스티커는 그림 (a)와 같이 2행 n열로 배치되어 있다. 상냥이는 스티커를 이용해 책상을 꾸미려고 한다.

상냥이가 구매한 스티커의 품질은 매우 좋지 않다. 스티커 한 장을 떼면, 그 스티커와 변을 공유하는 스티커는 모두 찢어져서 사용할 수 없게 된다. 즉, 뗀 스티커의 왼쪽, 오른쪽, 위, 아래에 있는 스티커는 사용할 수 없게 된다.

https://www.acmicpc.net/upload/images/sticker.png

모든 스티커를 붙일 수 없게된 상냥이는 각 스티커에 점수를 매기고, 점수의 합이 최대가 되게 스티커를 떼어내려고 한다. 먼저, 그림 (b)와 같이 각 스티커에 점수를 매겼다. 상냥이가 뗄 수 있는 스티커의 점수의 최댓값을 구하는 프로그램을 작성하시오. 즉, 2n개의 스티커 중에서 점수의 합이 최대가 되면서 서로 변을 공유 하지 않는 스티커 집합을 구해야 한다.

위의 그림의 경우에 점수가 50, 50, 100, 60인 스티커를 고르면, 점수는 260이 되고 이 것이 최대 점수이다. 가장 높은 점수를 가지는 두 스티커 (100과 70)은 변을 공유하기 때문에, 동시에 뗄 수 없다.

입력

첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스의 첫째 줄에는 n (1 ≤ n ≤ 100,000)이 주어진다. 다음 두 줄에는 n개의 정수가 주어지며, 각 정수는 그 위치에 해당하는 스티커의 점수이다. 연속하는 두 정수 사이에는 빈 칸이 하나 있다. 점수는 0보다 크거나 같고, 100보다 작거나 같은 정수이다.

출력

각 테스트 케이스 마다, 2n개의 스티커 중에서 두 변을 공유하지 않는 스티커 점수의 최댓값을 출력한다.

예제

예제 입력 1

1
2
3
4
5
6
7
8
2
5
50 10 100 20 40
30 50 70 10 60
7
10 30 10 50 100 20 40
20 40 30 50 60 20 80

예제 출력 1

1
2
260
290

내 코드

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
const input = require("fs")
.readFileSync("/dev/stdin")
.toString()
.trim()
.split("\n");
const T = +input.shift();
function sticker(n, arr) {
let DP = Array.from({ length: 2 }, () => Array(n).fill(0));

DP[0][1] = arr[0][0];
DP[1][1] = arr[1][0];
for (let i = 2; i <= n; i++) {
DP[0][i] = Math.max(DP[1][i - 1], DP[1][i - 2]) + +arr[0][i - 1];
DP[1][i] = Math.max(DP[0][i - 1], DP[0][i - 2]) + +arr[1][i - 1];
}
return Math.max(...DP.flat(1));
}

let answer = [];
for (let i = 0; i < T; i++) {
let k = input.splice(0, 1);
let arr = [];
arr.push(input.splice(0, 1).join("").split(" ").map(Number));
arr.push(input.splice(0, 1).join("").split(" ").map(Number));
answer.push(sticker(k, arr));
}

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

해설

DP 배열은 2차원 배열이고 2n 스티커이기 때문에, DP는 2행으로 구성된다.

  1. DP[0][1]은 2n 스티커에서 0번째 행의 1열의 스티커 점수를 나타낸다.
  2. DP[1][1]은 2n 스티커에서 1번째 행의 1열 스티커 점수를 나타낸다.

예시 이미지

댓글 공유

Copyrights © 2023 loco9939. All Rights Reserved.

loco9939

author.bio


author.job