N으로 나누었을 때 나머지와 몫이 같은 모든 자연수의 합을 구하는 프로그램을 작성하시오. 예를 들어 N=3일 때, 나머지와 몫이 모두 같은 자연수는 4와 8 두 개가 있으므로, 그 합은 12이다.
입력:
첫째 줄에 2,000,000 이하의 자연수 N이 주어진다.
출력:
첫 줄에 구하고자 하는 수를 출력한다.
풀이방법:
몫과 나머지가 같다고 가정한 뒤에 역으로 그 자연수 값을 찾도록 하면 된다. 나머지가 나올 수 있는 경우의 수는 N일 때 0~N-1까지 있다. 따라서 몫과 나머지가 같은 수는 i*(N)+i, i는 0부터 N-1까지의 수로 구할 수 있다. 이는 반복문 하나만 사용하면 구할 수 있다.
어떤 수 X가 주어졌을 때, X의 모든 자리수가 역순이 된 수를 얻을 수 있다. Rev(X)를 X의 모든 자리수를 역순으로 만든는 함수라고 하자. 예를 들어, X=123일 때, Rev(X) = 321이다. 그리고, X=100일 때, Rev(X) = 1이다.
두 양의 정수 X와 Y가 주어졌을 때, Rev(Rev(X) + Rev(Y))를 구하는 프로그램을 작성하시오.
입력:
첫째 줄에 수 X와 Y가 주어진다. X와 Y는 1,000보다 작거나 같은 자연수이다.
출력:
첫째 줄에 문제의 정답을 출력한다.
풀이방법:
파이썬에 문자열을 뒤집는 방법은 크게 두가지가 있다. 첫번째는 문자열을 배열로 바꾼 뒤에 reverse로 뒤집고 다시 join을 사용해서 문자열로 만드는 방법이다. 이 방법은 번거로운 작업이 많이 필요하다. 두번째는 슬라이싱의 특징을 이용하는 방법이다. [ : ]와 같이 사용하면 해당 문자열의 전체를 의미하게 된다. 이 때 [ : :-1]와 같이 사용하면 뒤에서부터 해당 문자열의 전체를 가져오게 된다. 즉 문자열을 뒤집게 된다. 따라서 이를 이용해서 문제가 요구하는 조건대로 연산을 진행하면 답을 구할 수 있다.
자연수 A를 B번 곱한 수를 알고 싶다. 단 구하려는 수가 매우 커질 수 있으므로 이를 C로 나눈 나머지를 구하는 프로그램을 작성하시오.
입력:
첫째 줄에 A,B,C가 빈 칸을 사이에 두고 순서대로 주어진다. A,B,C는 모두 2,147,483,647 이하의 자연수이다.
출력:
첫째 줄에 A를 B번 곱한 수를 C로 나눈 나머지를 출력한다.
풀이방법:
주어질 A,B,C의 값이 매우 크므로 pow 연산을 활용하는 것은 시간초과가 발생하게 될 것이다. 따라서 효율적인 연산이 필요하다. 그러면서 사용하게 되는 것이 모듈러 연산의 분배법칙이다.
모듈러 X=x1*x2라고 가정하자. 그러면 X mod y = (x1 mod y)*(x2 mod y) mod y 가 성립한다. 이 것과 10^n*10^m=10^(n+m)임을 사용하면 시간복잡도를 O((logN)^2)까지 줄일 수 있다.
우선 지수를 2의 지수 단위로 분할한다. 이 문제의 예시와 같은 경우 11은 8+2+1로 482는 256+128+64+32+2와 같이 분할할 수 있다. 즉 10^11 mod 12 = (10^8 mod 12)(10^2 mod 12)(10^1 mod 12) mod 12 이고, 10^482 mod 12 = (10^256 mod 12)(10^128 mod 12)(10^64 mod 12)(10^32 mod 12)(10^2 mod 12) mod 12가 된다.
2의 지수를 사용하는 것에는 이유가 있다. 10^1부터 DP 방식을 사용하면 나머지의 값들도 쉽게 구할 수 있기 때문이다. 10^2 mod 12 = (10^1 mod 12)(10^1 mod 12) mod 12 이고 10^4 mod 12 = (10^2 mod 12)(10^2 mod 12) mod 12 ...와 같이 구하면 된다.
위와 같이 dp table을 다 채우고 난 뒤에 해당하는 값들만 곱한뒤에 다시 c로 나누면 나머지를 출력하면 된다.
서로 다른 N개의 자연수의 합이 S라고 한다. S를 알 때, 자연수 N의 최댓값은 얼마일까?
입력:
첫째 줄에 자연수 S(1<=S<=4294967295)가 주어진다.
출력:
첫째 줄에 자연수 N의 최댓값을 출력한다.
풀이방법:
최대한 많은 서로 다른 수를 사용하며 그 합들이 S가 되도록 만들기 위해서는 1부터 차례대로 값을 더하는 것이 가장 많이 사용할 수 있다. 즉 예를 들어 11을 만들기 위해서는 1+2+3+4+1=11과 같이 사용하는 것이 N이 최대가 된다. 하지만 1을 중복해서 사용했다. 그래서 이 1을 4에다가 붙여서 다음과 같이 식을 구성하고 이 것이 최댓값이 되게 된다. (1+2+3+5=11)
따라서 S를 알 때, 자연수 N의 최댓값을 구하기 위해서 일반화를 할 수 있다. 1+2+ .... + n의 합은 S를 넘지 않는다. 즉 1+2+ .... + n +a =S가 되게 되는 것이다. 이 a를 항상 n에 붙임으로써 N의 최댓값을 구할 수 있다. 즉 1부터 n까지의 합이 S와 근접할 때 N의 최댓값이 된다.
1+2 + .... + n = ((n+1)*n)/2 이므로 이를 활용해서 m을 추정할 수 있고 이 값을 하나씩 감소시키며 n을 찾을 수 있다.
두 정수 N과 F가 주어진다. 지민이는 정수 N의 가장 뒤 두 자리를 적절히 바꿔서 N을 F로 나누어 떨어지게 만들려고 한다. 만약 가능한 것이 여러 가지이면, 뒤 두 자리를 가능하면 작게 만들려고 한다.
예를 들어, N=275이고, F=5이면, 답은 00이다. 200이 5로 나누어 떨어지기 때문이다. N=1021이고, F=11이면, 정답은 01인데, 1001이 11로 나누어 떨어지기 때문이다.
입력:
첫째 줄에 N, 둘째 줄에 F가 주어진다. N은 100보다 크거나 같고, 2,000,000,000보다 작거나 같은 자연수다. F는 100보다 작거나 같은 자연수이다.
출력:
첫째 줄에 마지막 두 자리를 모두 출력한다. 한자리이면 앞에 0을 추가해서 두 자리로 만들어야 한다.
풀이방법:
N을 입력 받은 뒤에 가장 뒤 두 자리를 00으로 만드는 것으로부터 시작한다. 이후 이 값이 F로 나누어지면(나머지가 0이면) 이 값을 출력하고, 나누어지지 않는다면(나머지가 0이 아니라면) F로 나눈 것의 몫에 1을 더한 것에 F를 곱한 것이 최솟값이면서 나누어 떨어지는 수가 된다. 이 때 한자리면 앞에 0을 추가해줘야 하므로 미리 string으로 바꿔서 이를 방지한다.
NxN 게임판에 수가 적혀져 있다. 이 게임의 목표는 가장 왼쪽 위 칸에서 가장 오른쪽 아래 칸으로 규칙에 맞게 점프를 해서 가는 것이다.
각 칸에 적혀있는 수는 현재 칸에서 갈 수 있는 거리를 의미한다. 반드시 오른쪽이나 아래쪽으로만 이동해야 한다. 0은 더 이상 진행을 막는 종착점이며, 항상 현재 칸에 적혀있는 수만큼 오른쪽이나 아래로 가야 한다. 한 번 점프를 할 때, 방향을 바꾸면 안 된다. 즉, 한 칸에서 오른쪽으로 점프를 하거나, 아래로 점프를 하는 두 경우만 존재한다.
가장 왼쪽 위 칸에서 가장 오른쪽 아래 칸으로 규칙에 맞게 이동할 수 있는 경로의 개수를 구하는 프로그램을 작성하시오.
입력:
첫째 줄에 게임 판의 크기 N(4<=N<=100)이 주어진다. 그 다음 N개 줄에는 각 칸에 적혀져 있는 수가 N개씩 주어진다. 칸에 적혀있는 수는 0보다 크거나 같고, 9보다 작거나 같은 정수이며, 가장 오른쪽 아래 칸에는 항상 0이 주어진다.
출력:
가장 왼쪽 위 칸에서 가장 오른쪽 아래 칸으로 문제의 규칙에 맞게 갈 수 있는 경로의 개수를 출력한다. 경로의 개수를 2^63-1보다 작거나 같다.
풀이방법:
dp를 사용해서 값을 누적시키면서 진행하면 답을 구할 수 있다. 갈 수 있는 경로의 수만 알면 되므로 dp[i][j]로 갈 수 있는 경우의 수를 누적시키면서 n,n으로 진행해나가면 된다. 따라서 시간복잡도는 O(N^2)이 될 것이다. dp[i][j]로 갈 수 있는 방법은 크게 두 가지다. 해당 위치를 기준으로 왼쪽에서 오거나 위쪽에서 오는 경우이다. 해당 칸에서 이동이 가능한지 알아보고 가능하다면 값을 더해주는 방식으로 진행하면 된다.
세로 R칸,가로 C칸으로 된 표 모양의 보드가 있다. 보드의 각 칸에는 대문자 알파벳이 하나씩 적혀 있고, 좌측 상단 칸(1행 1열)에는 말이 놓여 있다.
말은 상하좌우로 인접한 네 칸 중의 한 칸으로 이동할 수 있는데, 새로 이동한 칸에 적혀 있는 알파벳은 지금까지 지나온 모든 칸에 적혀 있는 알파벳과는 달라야 한다. 즉, 같은 알파벳이 적힌 칸을 두 번 지날 수 없다.
좌측 상단에서 시작해서, 말이 최대한 몇 칸을 지날 수 있는지를 구하는 프로그램을 작성하시오. 말이 지나는 칸은 좌측 상단의 칸도 포함된다.
입력:
첫째 줄에 R과 C가 빈칸을 사이에 두고 주어진다. (1<=R,C<=20)둘째 줄부터 R개의 줄에 걸쳐서 보드에 적혀 있는 C개의 대문자 알파벳들이 빈칸 없이 주어진다.
출력:
첫째 줄에 말이 지날 수 있는 최대의 칸 수를 출력한다.
풀이방법:
제일 많이 파고 들어가야 하는 문제이므로 DFS와 백트래킹을 사용하는 것이 적합하다. DFS를 사용해서 한 번 깊게 파고 난 뒤에 움직이지 못하는 경우가 된다면 다시 되돌아와서 다른 곳으로 깊게 파고 들어가도록 한다. 이때부터는 최대로 깊게 들어간 기록이 있으므로 이 기록을 넘길 때에만 값을 갱신하도록 하였다. 이렇게 모두 탐색을 마치고 더 이상 이동할 곳이 없다면 출력하도록 했다.
바로 어제 최백준 조교가 방 열쇠를 주머니에 넣은 채 깜빡하고 서울로 가 버리는 황당한 상황에 직면한 조교들은, 702호에 새로운 보안 시스템을 설치하기로 하였다. 이 보안 시스템은 열쇠가 아닌 암호로 동작하게 되어 있는 시스템이다.
암호는 서로 다른 L개의 알파벳 소문자들로 구성되며 최소 한 개의 모음과 최소 두 개의 자음으로 구성되어 있다고 알려져 있다. 또한 정렬된 문자열을 선호하는 조교들의 성향으로 미루어 보아 암호를 이루는 알파벳이 암호에서 증가하는 순서로 배열되었을 것이라고 추측된다. 즉, abc는 가능성이 있는 암호이지만 bac는 그렇지 않다.
새 보안 시스템에서 조교들이 암호로 사용했을 법한 문자의 종류는 C가지가 있다고 한다. 이 알파벳을 입수한 민식, 영식 형제는 조교들의 방에 침투하기 위해 암호를 추측해 보려고 한다. C개의 문자들이 모두 주어졌을 때, 가능성 있는 암호들을 모두 구하는 프로그램을 작성하시오.
입력:
첫째 줄에 두 정수 L, C가 주어진다. (3<=L<=C<=15) 다음 줄에는 C개의 문자들이 공백으로 구분되어 주어진다. 주어지는 문자들은 알파벳 소문자이며, 중복되는 것은 없다.
출력:
각 줄에 하나씩, 사전식으로 가능성 있는 암호를 모두 출력한다.
풀이 방법:
재귀적인 방법으로 암호를 만들고, 이 암호가 옳은 암호인지 판단하는 check라는 함수를 만들었다. 암호를 만들다가 길이가 L이 된다면 check로 옳은 암호인지 판단을 하고 맞다면 출력, 아니면 끝내도록 했다.
오늘은 스타트링크에 다니는 사람들이 모여서 축구를 해보려고 한다. 축구는 평일 오후에 하고 의무 참석도 아니다. 축구를 하기 위해 모인 사람은 총 N명이고 신기하게도 N은 짝수이다. 이제 N/2명으로 이루어진 스타트팀과 링크 팀으로 사람들을 나눠야 한다.
BOJ를 운영하는 회사 답게 사람에게 번호를 1부터 N까지로 배정했고, 아래와 같은 능력치를 조사했다. 능력치 Sij는 i번 사람과 j번 사람이 같은 팀에 속했을 때, 팀에 더해지는 능력치이다. 팀의 능력치는 팀에 속한 모든 쌍의 능력치 Sij의 합이다. Sij는 Sji와 다를 수도 있으며, i번 사람과 j번 사람이 같은 팀에 속했을 때, 팀에 더해지는 능력치는 Sij와 Ski이다.
N=4이고, S가 아래와 같은 경우를 살펴보자.
예를 들어, 1,2번이 스타트 팀, 3, 4번이 링크 팀에 속한 경우에 두 팀의 능력치는 아래와 같다.
스타트 팀: S12+S21 = 1+ 4 = 5
링크 팀: S34 + S43 = 2 + 5 = 7
1,3 번이 스타팀, 2,4번이 링크 팀에 속하면, 두 팀의 능력치는 아래와 같다.
스타트 팀: S13+S31 = 2+ 7 = 9
링크 팀: S24 + S42 = 6 + 4 = 10
축구를 재미있게 하기 위해서 스타트 팀의 능력치와 링크 팀의 능력치의 차이를 최소로 하려고 한다. 위의 예제와 같은 경우에는 1,4번이 스타트 팀, 2,3 번 팀이 링크 팀에 속하면 스타트 팀의 능력치는 6, 링크 팀의 능력치는 6의 되어서 차이가 0이 되고 이 값이 최소이다.
입력:
첫째 줄에 N(4<=N<=20, N은 짝수)이 주어진다. 둘째 줄부터 N개의 줄에 S가 주어진다. 각 줄은 N개의 수로 이루어져 있고, i번 줄의 j번째 수는 Sij 이다. Sii는 항상 0이고, 나머지 Sij는 1보다 크거나 같고, 100보다 작거나 같은 정수이다.
출력:
첫째 줄에 스타트 팀과 링크 팀의 능력치의 차이의 최솟값을 출력한다.
풀이 방법:
N은 최대 20이므로 나올 수 있는 조합의 경우의 수는 20C10이다. 이 정도의 수를 반복하는 것은 충분히 가능하기 때문에 브루트포스로 풀어도 상관없을 것 같았다.
우선 python의 itertools를 사용해서 나올 수 있는 조합을 만들었다. 그리고 set을 사용해서 스타트팀과 링크 팀으로 구분을 했고, 스타트팀과 링크 팀을 이중 반복문을 통해서 시너지의 합을 구했다. 그리고 시너지간의 차를 배열에 담았다.위 작업을 모두 마치고 나서 배열의 min을 출력하도록 하였다.
수빈이는 동생과 숨바꼭질을 하고 있다. 수빈이는 현재 점 N()<=N<=100,000)에 있고, 동생은 점 K(0<=K<=100,000)에 있다. 수빈이는 걷거나 순간이동을 할 수 있다. 만약 수빈이의 위치가 X일 때 걷는다면 1초 후에 X-1 또는 X+1로 이동하게 된다. 순간이동을 하는 경우에는 1초 후에 2*X의 위치로 이동하게 된다.
수빈이와 동생의 위치가 주어졌을 때, 수빈이가 동생을 찾을 수 있는 가장 빠른 시간이 몇 초 후인지 구하는 프로그램을 작성하시오.
입력:
첫 번째 줄에 수빈이가 있는 위치 N과 동생이 있는 위치 K가 주어진다. N과 K는 정수이다.
출력:
수빈이가 동생을 찾는 가장 빠른 시간을 출력한다.
풀이 방법:
여러 행위를 할 수 있는데 가장 빠른 방법을 찾는 문제는 대부분 BFS로 풀리는 경우가 많다. 따라서 이 문제도 X-1, X+1, 2X로 이동할 수 있는데 가장 빠른 시간을 찾기 때문에 BFS로 풀어야 한다.
한 layer마다 Queue의 값에 따라 이동할 수 있는 위치를 새로 queue에 넣는다. 이 과정을 반복하다가 원하는 위치로 이동했다면(dist[k]의 값이 갱신 되었다면) queue를 종료하도록 해서 답을 출력하도록 했다.