모터는 1분에 R_in번 돌고, 기계는 1분에 정확히 R_out번 돌아야 한다.
그 사이를 기어 열차로 잇는다.
열차의 한 단은 톱니 수가 서로 다른 기어 두 개, 구동 기어 a(톱니 a개)와 따라 도는 기어 b(톱니 b개)로 이루어지고, 그 단을 지나면 회전수가 a/b배가 된다.
쓸 수 있는 기어의 톱니 수가 m가지 주어지고, 같은 크기의 기어는 몇 개든 있다(같은 단을 여러 번 써도 된다).
열차는 0단부터 3단까지 쓸 수 있고, 출력 회전수는 R_in × (각 단의 a/b를 모두 곱한 값)이다.
단의 순서는 결과에 상관이 없으므로, 같은 단들을 순서만 바꾼 열차는 같은 열차로 센다.
출력 회전수가 정확히 R_out이 되는 열차 가운데 가장 적은 단 수 k와, 단이 k개인 그런 열차의 수를 빈칸 하나로 띄워 출력하라.
0단 열차(아무 단도 없음)는 R_in = R_out일 때만 맞고, 그때 답은 "0 1"이다.
3단 이하로 만들 수 없으면 -1을 출력한다.
입력
첫 줄에 R_in과 R_out, 둘째 줄에 m, 셋째 줄에 서로 다른 톱니 수 m개. 1 ≤ R_in, R_out ≤ 10,000, 1 ≤ m ≤ 8, 6 ≤ 톱니 수 ≤ 200
출력
"k 개수" 또는 -1
예시 1 · stdin
640 250
3
16 20 32
stdout
2 1
예시 2 · stdin
800 400
4
6 12 24 48
stdout
1 3
main.py
오류 목록00F8 ↓ · ⇧F8 ↑
입력(stdin)
실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).
$ 준비됐어요
코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.
다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이
단 하나는 많아야 8 × 7 = 56가지라 3단까지 모두 골라 봐도 3만 가지 남짓이에요. 그래서 재귀로 단을 하나씩 고르며 모두 해 봐요. 다음 단은 지금 고른 단의 번호부터만 고르면(번호가 줄지 않게) 순서만 바뀐 열차를 두 번 세지 않아요. 비교는 분수로 해요: 바라는 비 R_out/R_in을 gcd로 기약분수로 줄여 두고, 단을 고를 때마다 분자·분모를 곱한 뒤 다시 gcd로 나눠요. 기약분수는 하나뿐이라 분자끼리, 분모끼리 같은지만 보면 돼요. 함정 ① 바라는 비를 줄이지 않으면 900/1200처럼 줄일 수 있는 입력에서 하나도 못 찾아요. ② 회전수를 실수로 곱해 가며 ==로 비교하면 (x * a) / b의 반올림 오차 때문에 딱 맞는 열차를 놓쳐요. JavaScript·TypeScript·크레이콘은 수가 모두 실수라 특히 조심해야 하는데, 정수만 곱하고 나누어떨어질 때만 나누면 2⁵³까지 정확해요. ③ 다음 단을 처음부터 다시 고르면 같은 열차를 순서마다 따로 세요. gcd는 Python math.gcd, C++17 std::gcd(<numeric>)가 있고, Java·C#·C·JavaScript·TypeScript·크레이콘은 유클리드 호제법을 직접 써요. 크레이콘은 수학.몫 대신 /를 써도 되는데, gcd로 나누면 늘 나누어떨어지기 때문이에요.
Pythonmain.py · 33 줄
from math import gcdr_in, r_out = map(int, input().split())m = int(input())teeth = list(map(int, input().split()))stages = [(a, b) for a in teeth for b in teeth if a != b] # (구동 기어, 따라 도는 기어)g = gcd(r_out, r_in)want = (r_out // g, r_in // g) # 바라는 비 = 출력 / 입력, 기약분수로def count_trains(start, left, num, den): """stages[start:]에서 left개를 더 골라(같은 단 여러 번 가능) 비가 want가 되는 열차 수. 고른 단의 번호가 줄지 않게 해서, 순서만 바뀐 열차를 두 번 세지 않는다.""" if left == 0: return 1 if (num, den) == want else 0 total = 0 for i in range(start, len(stages)): a, b = stages[i] n2, d2 = num * a, den * b c = gcd(n2, d2) total += count_trains(i, left - 1, n2 // c, d2 // c) # 늘 기약분수로 줄여 둔다 return totalanswer = "-1"for k in range(4): c = count_trains(0, k, 1, 1) if c > 0: answer = f"{k} {c}" breakprint(answer)
JavaScriptmain.js · 38 줄
const data = require("fs").readFileSync(0, "utf8").trim().split(/\s+/).map(Number);const [rIn, rOut, m] = data;const teeth = data.slice(3, 3 + m);function gcd(a, b) { while (b !== 0) [a, b] = [b, a % b]; return a;}const stages = []; // [구동 기어, 따라 도는 기어]for (const a of teeth) for (const b of teeth) if (a !== b) stages.push([a, b]);const g = gcd(rOut, rIn);const wantNum = rOut / g; // 바라는 비 = 출력 / 입력, 기약분수로const wantDen = rIn / g;// stages[start..]에서 left개를 더 골라(같은 단 여러 번 가능) 비가 바라는 비가 되는 열차 수.// 고른 단의 번호가 줄지 않게 해서, 순서만 바뀐 열차를 두 번 세지 않는다function countTrains(start, left, num, den) { if (left === 0) return num === wantNum && den === wantDen ? 1 : 0; let total = 0; for (let i = start; i < stages.length; i++) { const [a, b] = stages[i]; const c = gcd(num * a, den * b); total += countTrains(i, left - 1, (num * a) / c, (den * b) / c); // 늘 기약분수로 줄여 둔다 } return total;}let answer = "-1";for (let k = 0; k <= 3; k++) { const c = countTrains(0, k, 1, 1); if (c > 0) { answer = `${k} ${c}`; break; }}console.log(answer);
TypeScriptmain.ts · 39 줄
import { readFileSync } from "node:fs";const data: number[] = readFileSync(0, "utf8").trim().split(/\s+/).map(Number);const [rIn, rOut, m] = data;const teeth: number[] = data.slice(3, 3 + m);function gcd(a: number, b: number): number { while (b !== 0) [a, b] = [b, a % b]; return a;}const stages: [number, number][] = []; // [구동 기어, 따라 도는 기어]for (const a of teeth) for (const b of teeth) if (a !== b) stages.push([a, b]);const g = gcd(rOut, rIn);const wantNum = rOut / g; // 바라는 비 = 출력 / 입력, 기약분수로const wantDen = rIn / g;// stages[start..]에서 left개를 더 골라(같은 단 여러 번 가능) 비가 바라는 비가 되는 열차 수.// 고른 단의 번호가 줄지 않게 해서, 순서만 바뀐 열차를 두 번 세지 않는다function countTrains(start: number, left: number, num: number, den: number): number { if (left === 0) return num === wantNum && den === wantDen ? 1 : 0; let total = 0; for (let i = start; i < stages.length; i++) { const [a, b] = stages[i]; const c = gcd(num * a, den * b); total += countTrains(i, left - 1, (num * a) / c, (den * b) / c); // 늘 기약분수로 줄여 둔다 } return total;}let answer = "-1";for (let k = 0; k <= 3; k++) { const c = countTrains(0, k, 1, 1); if (c > 0) { answer = `${k} ${c}`; break; }}console.log(answer);
JavaMain.java · 51 줄
import java.util.*;public class Main { static List<int[]> stages = new ArrayList<>(); // {구동 기어, 따라 도는 기어} static long wantNum, wantDen; static long gcd(long a, long b) { while (b != 0) { long t = a % b; a = b; b = t; } return a; } // stages[start..]에서 left개를 더 골라(같은 단 여러 번 가능) 비가 바라는 비가 되는 열차 수. // 고른 단의 번호가 줄지 않게 해서, 순서만 바뀐 열차를 두 번 세지 않는다 static long countTrains(int start, int left, long num, long den) { if (left == 0) return num == wantNum && den == wantDen ? 1 : 0; long total = 0; for (int i = start; i < stages.size(); i++) { long n2 = num * stages.get(i)[0], d2 = den * stages.get(i)[1]; long c = gcd(n2, d2); total += countTrains(i, left - 1, n2 / c, d2 / c); // 늘 기약분수로 줄여 둔다 } return total; } public static void main(String[] args) { Scanner sc = new Scanner(System.in); long rIn = sc.nextLong(), rOut = sc.nextLong(); int m = sc.nextInt(); int[] teeth = new int[m]; for (int i = 0; i < m; i++) teeth[i] = sc.nextInt(); for (int a : teeth) for (int b : teeth) if (a != b) stages.add(new int[] {a, b}); long g = gcd(rOut, rIn); wantNum = rOut / g; // 바라는 비 = 출력 / 입력, 기약분수로 wantDen = rIn / g; String answer = "-1"; for (int k = 0; k <= 3; k++) { long c = countTrains(0, k, 1, 1); if (c > 0) { answer = k + " " + c; break; } } System.out.println(answer); }}
C#Main.cs · 54 줄
using System;using System.Collections.Generic;using System.Linq;class Program{ static readonly List<(long a, long b)> stages = new List<(long a, long b)>(); // (구동 기어, 따라 도는 기어) static long wantNum, wantDen; static long Gcd(long a, long b) { while (b != 0) (a, b) = (b, a % b); return a; } // stages[start..]에서 left개를 더 골라(같은 단 여러 번 가능) 비가 바라는 비가 되는 열차 수. // 고른 단의 번호가 줄지 않게 해서, 순서만 바뀐 열차를 두 번 세지 않는다 static long CountTrains(int start, int left, long num, long den) { if (left == 0) return num == wantNum && den == wantDen ? 1 : 0; long total = 0; for (int i = start; i < stages.Count; i++) { long n2 = num * stages[i].a, d2 = den * stages[i].b; long c = Gcd(n2, d2); total += CountTrains(i, left - 1, n2 / c, d2 / c); // 늘 기약분수로 줄여 둔다 } return total; } static void Main() { long[] r = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries).Select(long.Parse).ToArray(); Console.ReadLine(); int[] teeth = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray(); foreach (int a in teeth) foreach (int b in teeth) if (a != b) stages.Add((a, b)); long g = Gcd(r[1], r[0]); wantNum = r[1] / g; // 바라는 비 = 출력 / 입력, 기약분수로 wantDen = r[0] / g; string answer = "-1"; for (int k = 0; k <= 3; k++) { long c = CountTrains(0, k, 1, 1); if (c > 0) { answer = k + " " + c; break; } } Console.WriteLine(answer); }}
C++main.cpp · 42 줄
#include <iostream>#include <numeric>#include <utility>#include <vector>std::vector<std::pair<long long, long long>> stages; // (구동 기어, 따라 도는 기어)long long wantNum, wantDen;// stages[start..]에서 left개를 더 골라(같은 단 여러 번 가능) 비가 바라는 비가 되는 열차 수.// 고른 단의 번호가 줄지 않게 해서, 순서만 바뀐 열차를 두 번 세지 않는다long long countTrains(size_t start, int left, long long num, long long den) { if (left == 0) return num == wantNum && den == wantDen ? 1 : 0; long long total = 0; for (size_t i = start; i < stages.size(); i++) { long long n2 = num * stages[i].first, d2 = den * stages[i].second; long long c = std::gcd(n2, d2); total += countTrains(i, left - 1, n2 / c, d2 / c); // 늘 기약분수로 줄여 둔다 } return total;}int main() { long long rIn, rOut; int m; std::cin >> rIn >> rOut >> m; std::vector<long long> teeth(m); for (auto& t : teeth) std::cin >> t; for (long long a : teeth) for (long long b : teeth) if (a != b) stages.push_back({a, b}); long long g = std::gcd(rOut, rIn); wantNum = rOut / g; // 바라는 비 = 출력 / 입력, 기약분수로 wantDen = rIn / g; for (int k = 0; k <= 3; k++) { long long c = countTrains(0, k, 1, 1); if (c > 0) { std::cout << k << ' ' << c << '\n'; return 0; } } std::cout << "-1\n";}
Cmain.c · 51 줄
#include <stdio.h>static int sa[56], sb[56], nstages = 0; /* 단: 구동 기어 sa, 따라 도는 기어 sb */static long long want_num, want_den;long long gcd(long long a, long long b) { while (b != 0) { long long t = a % b; a = b; b = t; } return a;}/* 단 start번부터 left개를 더 골라(같은 단 여러 번 가능) 비가 바라는 비가 되는 열차 수. 고른 단의 번호가 줄지 않게 해서, 순서만 바뀐 열차를 두 번 세지 않는다 */long long count_trains(int start, int left, long long num, long long den) { if (left == 0) return num == want_num && den == want_den; long long total = 0; for (int i = start; i < nstages; i++) { long long n2 = num * sa[i], d2 = den * sb[i]; long long c = gcd(n2, d2); total += count_trains(i, left - 1, n2 / c, d2 / c); /* 늘 기약분수로 줄여 둔다 */ } return total;}int main(void) { long long r_in, r_out; int m, teeth[8]; scanf("%lld %lld %d", &r_in, &r_out, &m); for (int i = 0; i < m; i++) scanf("%d", &teeth[i]); for (int i = 0; i < m; i++) for (int j = 0; j < m; j++) if (i != j) { sa[nstages] = teeth[i]; sb[nstages++] = teeth[j]; } long long g = gcd(r_out, r_in); want_num = r_out / g; /* 바라는 비 = 출력 / 입력, 기약분수로 */ want_den = r_in / g; for (int k = 0; k <= 3; k++) { long long c = count_trains(0, k, 1, 1); if (c > 0) { printf("%d %lld\n", k, c); return 0; } } puts("-1"); return 0;}
Craykonmain.cray · 64 줄
최대공약수(a, b){ 동안 (b != 0) { t = a % b; a = b; b = t; } 돌려주기 a;}// stages[start..]에서 left개를 더 골라(같은 단 여러 번 가능) 비가 바라는 비가 되는 열차 수.// 고른 단의 번호가 줄지 않게 해서, 순서만 바뀐 열차를 두 번 세지 않는다열차세기(start, left, num, den){ 만약 (left == 0) { 만약 (num == wantNum && den == wantDen) { 돌려주기 1; } 돌려주기 0; } total = 0; 반복 (s = start; s < stages.개수; s++) { n2 = num * stages[s][0]; d2 = den * stages[s][1]; c = 최대공약수(n2, d2); total += 열차세기(s, left - 1, n2 / c, d2 / c); // 늘 기약분수로 줄여 둔다(나누어떨어져서 / 로 된다) } 돌려주기 total;}r = 콘솔.수들읽기();rIn = r[0];rOut = r[1];m = 콘솔.줄읽기().수로변환();teeth = 콘솔.수들읽기();stages = []; // [구동 기어, 따라 도는 기어]각각 (a 에서 teeth){ 각각 (b 에서 teeth) { 만약 (a != b) { stages.넣기([a, b]); } }}g = 최대공약수(rOut, rIn);wantNum = rOut / g; // 바라는 비 = 출력 / 입력, 기약분수로wantDen = rIn / g;answer = "-1";반복 (k = 0; k <= 3; k++){ cnt = 열차세기(0, k, 1, 1); 만약 (cnt > 0) { answer = k + " " + cnt; 그만; }}콘솔.쓰기(answer);