서로 다른 값의 동전 k종류가 있고, 종류마다 얼마든지 쓸 수 있다. 동전 몇 개를 골라 합이 정확히 N원이 되게 하는 방법의 수를 1,000,000,007로 나눈 나머지를 출력하라. 쓰는 동전의 종류별 개수가 같으면 같은 방법이다(순서는 따지지 않는다: 1+2와 2+1은 한 가지). 동전을 하나도 쓰지 않는 것도 방법이므로 N = 0이면 답은 1이다. 만들 수 없으면 0을 출력한다.
첫 줄에 N과 k, 둘째 줄에 동전 값 c₁ … c_k가 빈칸으로 나뉘어 주어진다.
입력
0 ≤ N ≤ 9,999, 1 ≤ k ≤ 100, 1 ≤ cᵢ ≤ 10,000, cᵢ는 모두 다르다
출력
방법의 수를 1,000,000,007로 나눈 나머지(정수 하나)
예시 1 · stdin
5 3
1 2 5
stdout
4
예시 2 · stdin
3 1
2
stdout
0
main.py
오류 목록00F8 ↓ · ⇧F8 ↑
입력(stdin)
실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).
$ 준비됐어요
코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.
다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이
ways[x] = 'x원을 만드는 방법 수'로 두고 ways[0] = 1(아무것도 안 씀)에서 시작해, 동전 c마다 x = c … N에 ways[x] += ways[x - c]를 해요. k × N ≤ 100만 번이라 모든 언어가 빨라요. 함정 둘: 반복의 바깥이 동전, 안쪽이 금액이어야 순서를 따지지 않는 수가 돼요 — 바꾸면 1+2와 2+1을 따로 세요. 그리고 방법 수는 금세 10¹⁸을 훌쩍 넘으니 더할 때마다% 1000000007를 해야 해요. 끝에서 한 번만 나누면 C·C++·Java·C#의 long은 넘쳐서 엉뚱한 값이 되고, JavaScript·TypeScript·크레이콘의 수(배정밀도)는 2^53을 넘으면서 정확하지 않게 돼요. Python만 정수 크기에 끝이 없어서 답은 맞지만, 수백 자리 수를 더하느라 느려져요. 두 값이 모두 1,000,000,007보다 작으면 합은 약 20억이라 32비트 int(약 21억)에 겨우 들어가요 — 그래서 여기서는 int로 충분하지만, 곱하거나 셋 이상 더하면 long/long long이 필요해요. 나머지 연산은 모두 %예요(크레이콘도 %). 배열 만들기: Python [0] * (n + 1), JS new Array(n + 1).fill(0), C++ vector<int>(n + 1, 0), Java·C# new int[n + 1], C static int ways[10000], 크레이콘 새목록(n + 1, 0) — N이 9,999까지라 크레이콘 목록 한도(10,000개)에 맞아요.
Pythonmain.py · 12 줄
MOD = 1_000_000_007n, k = map(int, input().split())coins = list(map(int, input().split()))# ways[x] = x원을 만드는 방법 수. 동전 종류를 바깥에 두면 순서만 다른 것을 한 번만 센다ways = [0] * (n + 1)ways[0] = 1for c in coins: for x in range(c, n + 1): ways[x] = (ways[x] + ways[x - c]) % MODprint(ways[n])
JavaScriptmain.js · 10 줄
const MOD = 1_000_000_007;const [n, k, ...coins] = require("fs").readFileSync(0, "utf8").trim().split(/\s+/).map(Number);// ways[x] = x원을 만드는 방법 수. 동전 종류를 바깥에 두면 순서만 다른 것을 한 번만 센다const ways = new Array(n + 1).fill(0);ways[0] = 1;for (const c of coins) { for (let x = c; x <= n; x++) ways[x] = (ways[x] + ways[x - c]) % MOD;}console.log(ways[n]);
TypeScriptmain.ts · 11 줄
import { readFileSync } from "node:fs";const MOD = 1_000_000_007;const [n, k, ...coins]: number[] = readFileSync(0, "utf8").trim().split(/\s+/).map(Number);// ways[x] = x원을 만드는 방법 수. 동전 종류를 바깥에 두면 순서만 다른 것을 한 번만 센다const ways: number[] = new Array(n + 1).fill(0);ways[0] = 1;for (const c of coins) { for (let x = c; x <= n; x++) ways[x] = (ways[x] + ways[x - c]) % MOD;}console.log(ways[n]);
JavaMain.java · 19 줄
import java.util.Scanner;public class Main { static final int MOD = 1_000_000_007; public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(), k = sc.nextInt(); // ways[x] = x원을 만드는 방법 수. 동전 종류를 바깥에 두면 순서만 다른 것을 한 번만 센다 int[] ways = new int[n + 1]; ways[0] = 1; for (int i = 0; i < k; i++) { int c = sc.nextInt(); // 두 값이 모두 MOD보다 작아서 합은 약 20억 — int(약 21억) 안에 든다 for (int x = c; x <= n; x++) ways[x] = (ways[x] + ways[x - c]) % MOD; } System.out.println(ways[n]); }}
C#Main.cs · 22 줄
using System;using System.Linq;class Program{ const int MOD = 1_000_000_007; static void Main() { int n = int.Parse(Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries)[0]); int[] coins = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray(); // ways[x] = x원을 만드는 방법 수. 동전 종류를 바깥에 두면 순서만 다른 것을 한 번만 센다 int[] ways = new int[n + 1]; ways[0] = 1; foreach (int c in coins) { for (int x = c; x <= n; x++) ways[x] = (ways[x] + ways[x - c]) % MOD; } Console.WriteLine(ways[n]); }}
C++main.cpp · 18 줄
#include <iostream>#include <vector>constexpr int MOD = 1'000'000'007;int main() { int n, k; std::cin >> n >> k; // ways[x] = x원을 만드는 방법 수. 동전 종류를 바깥에 두면 순서만 다른 것을 한 번만 센다 std::vector<int> ways(n + 1, 0); ways[0] = 1; for (int i = 0; i < k; i++) { int c; std::cin >> c; for (int x = c; x <= n; x++) ways[x] = (ways[x] + ways[x - c]) % MOD; } std::cout << ways[n] << '\n';}
Cmain.c · 20 줄
#include <stdio.h>#define MOD 1000000007#define MAXN 9999int main(void) { static int ways[MAXN + 1]; int n, k; scanf("%d %d", &n, &k); /* ways[x] = x원을 만드는 방법 수. 동전 종류를 바깥에 두면 순서만 다른 것을 한 번만 센다 */ ways[0] = 1; for (int i = 0; i < k; i++) { int c; scanf("%d", &c); /* 두 값이 모두 MOD보다 작아서 합은 약 20억 — int(약 21억) 안에 든다 */ for (int x = c; x <= n; x++) ways[x] = (ways[x] + ways[x - c]) % MOD; } printf("%d\n", ways[n]); return 0;}
Craykonmain.cray · 16 줄
MOD = 1000000007;첫줄 = 콘솔.수들읽기();n = 첫줄[0];coins = 콘솔.수들읽기();// ways[x] = x원을 만드는 방법 수. 동전 종류를 바깥에 두면 순서만 다른 것을 한 번만 센다ways = 새목록(n + 1, 0);ways[0] = 1;각각 (c 에서 coins){ 반복 (x = c; x <= n; x++) { ways[x] = (ways[x] + ways[x - c]) % MOD; }}콘솔.쓰기(ways[n]);