有 n 条丝带,长度为 a₁, …, aₙ。 要把丝带剪成至少 k 段,且每段长度都是同一个正整数 L。 丝带不能拼接,剪剩的部分丢掉(长度为 a 的丝带能剪出 a 除以 L 的商那么多段)。 输出能做到的最大 L。 若 L = 1 也剪不出 k 段,输出 0。
输入
第一行 n 和 k,第二行 a₁ … aₙ。 1 ≤ n ≤ 10,000,1 ≤ aᵢ ≤ 2,000,000,000,1 ≤ k ≤ 20,000,000,000,000
输出
最大的 L,或 0
样例 1 · stdin
3 4
5 5 5
stdout
2
样例 2 · stdin
2 7
3 3
stdout
0
main.py
错误列表00F8 ↓ · ⇧F8 ↑
输入(stdin)
运行时这些行会依次作为 input()/标准输入传入(运行中不会等待输入)。
$ 就绪
请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。
其他语言怎么写?查看各语言题解 · 8 种语言题解
把 L 从 1 一个个增大最多要 20 亿次。 L 越大段数越少,所以「是否至少 k 段」前面为真、后面为假,用二分查找 31 次就能找到。 把条件作为函数传入的查找函数单独写出来,别的题也能直接用:Python 直接传函数名,JavaScript/TypeScript 用箭头函数 (x: number) => boolean,Java 用 IntPredicate 和 ok.test(mid),C# Func<int, bool>,C++ std::function<bool(int)> 配合 lambda,C 用函数指针 int (*ok)(int),Craykon 把函数名当作值传入,用 ok(mid) 调用。 陷阱是溢出。 ① 中点 (lo + hi) / 2:即使长度能放进 int(约 21 亿),lo + hi 也会到 40 亿,在 Java、C#、C、C++ 中溢出——要写 lo + (hi - lo) / 2。 JavaScript 的 (lo + hi) >> 1 也会转成 32 位整数,同样出错(用 Math.floor)。 Python 和 Craykon 不会溢出。 ② 段数可达 2×10¹³,需要 long/long long。 最后,若 L = 1 也不够,答案是 0 而不是 1。
Pythonmain.py · 22 行
def last_true(lo, hi, ok): """lo..hi 에서 ok(x)가 참인 가장 큰 x. ok는 앞쪽이 참, 뒤쪽이 거짓이어야 한다. 없으면 lo - 1.""" answer = lo - 1 while lo <= hi: mid = (lo + hi) // 2 if ok(mid): answer = mid lo = mid + 1 else: hi = mid - 1 return answern, k = map(int, input().split())a = list(map(int, input().split()))def enough(length): return sum(x // length for x in a) >= kprint(last_true(1, max(a), enough))
JavaScriptmain.js · 18 行
// lo..hi 에서 ok(x)가 참인 가장 큰 x. ok는 앞쪽이 참, 뒤쪽이 거짓이어야 한다. 없으면 lo - 1.function lastTrue(lo, hi, ok) { let answer = lo - 1; while (lo <= hi) { const mid = Math.floor((lo + hi) / 2); if (ok(mid)) { answer = mid; lo = mid + 1; } else { hi = mid - 1; } } return answer;}const [n, k, ...a] = require("fs").readFileSync(0, "utf8").trim().split(/\s+/).map(Number);const enough = (length) => a.reduce((sum, x) => sum + Math.floor(x / length), 0) >= k;console.log(lastTrue(1, Math.max(...a), enough));
TypeScriptmain.ts · 20 行
import { readFileSync } from "node:fs";// lo..hi 에서 ok(x)가 참인 가장 큰 x. ok는 앞쪽이 참, 뒤쪽이 거짓이어야 한다. 없으면 lo - 1.function lastTrue(lo: number, hi: number, ok: (x: number) => boolean): number { let answer = lo - 1; while (lo <= hi) { const mid = Math.floor((lo + hi) / 2); if (ok(mid)) { answer = mid; lo = mid + 1; } else { hi = mid - 1; } } return answer;}const [n, k, ...a]: number[] = readFileSync(0, "utf8").trim().split(/\s+/).map(Number);const enough = (length: number): boolean => a.reduce((sum, x) => sum + Math.floor(x / length), 0) >= k;console.log(lastTrue(1, Math.max(...a), enough));
JavaMain.java · 42 行
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.StringTokenizer;import java.util.function.IntPredicate;public class Main { // lo..hi 에서 ok(x)가 참인 가장 큰 x. 없으면 lo - 1. static int lastTrue(int lo, int hi, IntPredicate ok) { int answer = lo - 1; while (lo <= hi) { int mid = lo + (hi - lo) / 2; // (lo + hi) / 2 는 int를 넘칠 수 있다 if (ok.test(mid)) { answer = mid; lo = mid + 1; } else { hi = mid - 1; } } return answer; } public static void main(String[] args) throws IOException { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(in.readLine()); int n = Integer.parseInt(st.nextToken()); long k = Long.parseLong(st.nextToken()); int[] a = new int[n]; int longest = 0; st = new StringTokenizer(in.readLine()); for (int i = 0; i < n; i++) { a[i] = Integer.parseInt(st.nextToken()); longest = Math.max(longest, a[i]); } IntPredicate enough = length -> { long pieces = 0; for (int x : a) pieces += x / length; return pieces >= k; }; System.out.println(lastTrue(1, longest, enough)); }}
C#Main.cs · 33 行
using System;using System.Linq;class Program{ // lo..hi 에서 ok(x)가 참인 가장 큰 x. 없으면 lo - 1. static int LastTrue(int lo, int hi, Func<int, bool> ok) { int answer = lo - 1; while (lo <= hi) { int mid = lo + (hi - lo) / 2; // (lo + hi) / 2 는 int를 넘칠 수 있다 if (ok(mid)) { answer = mid; lo = mid + 1; } else { hi = mid - 1; } } return answer; } static void Main() { long k = long.Parse(Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries)[1]); int[] a = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray(); Func<int, bool> enough = length => a.Sum(x => (long)(x / length)) >= k; Console.WriteLine(LastTrue(1, a.Max(), enough)); }}
C++main.cpp · 33 行
#include <algorithm>#include <functional>#include <iostream>#include <vector>// lo..hi 에서 ok(x)가 참인 가장 큰 x. 없으면 lo - 1.int lastTrue(int lo, int hi, const std::function<bool(int)>& ok) { int answer = lo - 1; while (lo <= hi) { int mid = lo + (hi - lo) / 2; // (lo + hi) / 2 는 int를 넘칠 수 있다 if (ok(mid)) { answer = mid; lo = mid + 1; } else { hi = mid - 1; } } return answer;}int main() { int n; long long k; std::cin >> n >> k; std::vector<int> a(n); for (int& x : a) std::cin >> x; auto enough = [&](int length) { long long pieces = 0; for (int x : a) pieces += x / length; return pieces >= k; }; std::cout << lastTrue(1, *std::max_element(a.begin(), a.end()), enough) << "\n";}
Cmain.c · 37 行
#include <stdio.h>static int n;static long long k;static int a[10000];/* lo..hi 에서 ok(x)가 참인 가장 큰 x. 없으면 lo - 1. ok는 함수 포인터로 받는다. */static int last_true(int lo, int hi, int (*ok)(int)) { int answer = lo - 1; while (lo <= hi) { int mid = lo + (hi - lo) / 2; /* (lo + hi) / 2 는 int를 넘칠 수 있다 */ if (ok(mid)) { answer = mid; lo = mid + 1; } else { hi = mid - 1; } } return answer;}static int enough(int length) { long long pieces = 0; for (int i = 0; i < n; i++) pieces += a[i] / length; return pieces >= k;}int main(void) { int longest = 0; scanf("%d %lld", &n, &k); for (int i = 0; i < n; i++) { scanf("%d", &a[i]); if (a[i] > longest) longest = a[i]; } printf("%d\n", last_true(1, longest, enough)); return 0;}
Craykonmain.cray · 40 行
// lo..hi 에서 ok(x)가 참인 가장 큰 x. ok는 앞쪽이 참, 뒤쪽이 거짓이어야 한다. 없으면 lo - 1.가장큰참(lo, hi, ok){ answer = lo - 1; 当 (lo <= hi) { mid = 数学.商(lo + hi, 2); 如果 (ok(mid)) { answer = mid; lo = mid + 1; } 否则 { hi = mid - 1; } } 返回 answer;}// 길이 length로 자르면 k조각 이상 나오나충분한가(length){ pieces = 0; 遍历 (x 在 a) { pieces += 数学.商(x, length); } 返回 pieces >= k;}첫줄 = 控制台.读数字();k = 첫줄[1];a = 控制台.读数字();longest = 0;遍历 (x 在 a){ longest = 数学.较大值(longest, x);}控制台.输出(가장큰참(1, longest, 충분한가));