圆桌周围摆着 n 把椅子,按顺时针方向从 0 到 n−1 编号。 从 n−1 号椅子顺时针走一格就是 0 号椅子。 先在 0 号椅子上放一颗糖。 之后,每次从刚放过糖的椅子顺时针走 k 格,在到达的椅子上放一颗糖。 如果到达的椅子上已经有糖,就不放并停下。 设 n 和 k 的最大公约数为 g,已知停下时放有糖的椅子恰好是编号为 g 的倍数的全部椅子(0 也算 g 的倍数)。 一行给出 n 和 k,用一个空格分开。 按顺序输出放有糖的椅子数,以及放有糖的椅子的编号中最大的一个,用一个空格分开,占一行。
输入
1 ≤ n ≤ 1,000,000,000,1 ≤ k ≤ 1,000,000,000(整数,只给出数字,没有逗号)。 k 可能比 n 大
输出
一行,放有糖的椅子数和其中最大的编号,用一个空格分开
样例 1 · stdin
12 8
stdout
3 8
样例 2 · stdin
5 10
stdout
1 0
main.py
错误列表00F8 ↓ · ⇧F8 ↑
输入(stdin)
运行时这些行会依次作为 input()/标准输入传入(运行中不会等待输入)。
$ 就绪
请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。
其他语言怎么写?查看各语言题解 · 8 种语言题解
有的语言有求最大公约数的函数,有的没有。 Python 直接用 math.gcd(n, k),C++ 用 <numeric> 里的 std::gcd(n, k)(C++17 起)。 JS、TS、C、Craykon 没有;Java 和 C# 只有大数类型的(BigInteger.gcd、BigInteger.GreatestCommonDivisor),所以对 int 通常自己写。 写法是辗转相除法(欧几里得算法)。 不断把 (a, b) 换成 (b, a % b),直到 b 为 0,剩下的 a 就是最大公约数。 第一个陷阱是替换的顺序。 写成 a = b; b = a % b; 时 a 已经变成了 b,于是算的是 b % b = 0,最大公约数总是得到 k。 样例 1 变成 1 4。 先把余数存进临时变量,或者像 Python a, b = b, a % b、JS/TS [a, b] = [b, a % b]、C# (a, b) = (b, a % b) 那样同时替换。 第二个陷阱是用反复相减代替取余。 对 1000000000 1 或 1 1000000000 这样的输入要减大约 10 亿次,无法在时限内结束。 用取余的话,这个范围内的任何输入几十次以内就结束。 第三个陷阱是不求最大公约数,直接用 k 计算。 样例 1 会得到 12 除以 8 的商 1 和 12 − 8 = 4,但答案是 3 8。 第四个陷阱是 Python 的 /。 n / g 即使整除也是浮点数,样例 1 会输出 3.0 8。 求商要用 n // g。 JS、TS 和 Craykon 的 / 也会除到小数,但值是整数时输出 3。 在 Craykon 中用 数学.商(n, g) 求商。
Pythonmain.py · 6 行
import mathn, k = map(int, input().split())g = math.gcd(n, k)# //는 몫(정수)이다. /를 쓰면 3.0처럼 실수가 된다print(n // g, n - g)
JavaScriptmain.js · 9 行
const [n, k] = require("fs").readFileSync(0, "utf8").trim().split(/\s+/).map(Number);// 유클리드 호제법: b가 0이 될 때까지 (a, b)를 (b, a % b)로 바꾼다let a = n;let b = k;while (b !== 0) { [a, b] = [b, a % b];}const g = a;console.log(`${n / g} ${n - g}`);
TypeScriptmain.ts · 10 行
import { readFileSync } from "node:fs";const [n, k]: number[] = readFileSync(0, "utf8").trim().split(/\s+/).map(Number);// 유클리드 호제법: b가 0이 될 때까지 (a, b)를 (b, a % b)로 바꾼다let a: number = n;let b: number = k;while (b !== 0) { [a, b] = [b, a % b];}const g: number = a;console.log(`${n / g} ${n - g}`);
JavaMain.java · 19 行
import java.util.Scanner;public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int k = sc.nextInt(); // 유클리드 호제법: b가 0이 될 때까지 (a, b)를 (b, a % b)로 바꾼다 int a = n; int b = k; while (b != 0) { int r = a % b; // 나머지를 먼저 담아 둔다 a = b; b = r; } int g = a; System.out.println((n / g) + " " + (n - g)); }}
C#Main.cs · 20 行
using System;class Program{ static void Main() { string[] p = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries); int n = int.Parse(p[0]); int k = int.Parse(p[1]); // 유클리드 호제법: b가 0이 될 때까지 (a, b)를 (b, a % b)로 바꾼다 int a = n; int b = k; while (b != 0) { (a, b) = (b, a % b); } int g = a; Console.WriteLine($"{n / g} {n - g}"); }}
C++main.cpp · 9 行
#include <iostream>#include <numeric>int main() { int n, k; std::cin >> n >> k; int g = std::gcd(n, k); // <numeric>, C++17부터 std::cout << n / g << " " << n - g << "\n";}
Cmain.c · 16 行
#include <stdio.h>int main(void) { int n, k; scanf("%d %d", &n, &k); /* 유클리드 호제법: b가 0이 될 때까지 (a, b)를 (b, a % b)로 바꾼다 */ int a = n, b = k; while (b != 0) { int r = a % b; /* 나머지를 먼저 담아 둔다 */ a = b; b = r; } int g = a; printf("%d %d\n", n / g, n - g); return 0;}
Craykonmain.cray · 14 行
수들 = 控制台.读数字();n = 수들[0];k = 수들[1];// 유클리드 호제법: b가 0이 될 때까지 (a, b)를 (b, a % b)로 바꾼다a = n;b = k;当 (b != 0){ r = a % b; // 나머지를 먼저 담아 둔다 a = b; b = r;}g = a;控制台.输出(数学.商(n, g) + " " + (n - g));