拼多多校招笔试真题 10.26 - 绳段拆分判定(C++/Py/Java /Js/Go)

绳段拆分判定

拼多多 10月26号 笔试真题 第二题

拼多多真题目录点击查看: 拼多多笔试真题题库目录|笔试题库 + 算法考点详解

题目内容

多多手里握着一根长度为 S S S 的绳子。

这根绳子允许切任意多刀,也允许保持原样、一刀都不动。每一次下刀,都是挑出当前还留着的某一截,把它的长度记作 y y y,再顺着正中分开,得到 ⌊ y 2 ⌋ \left\lfloor \frac{y}{2} \right\rfloor ⌊2y⌋ 与 ⌈ y 2 ⌉ \left\lceil \frac{y}{2} \right\rceil ⌈2y⌉ 这两截;前一个记号会把小数部分丢掉,后一个记号只要出现小数就往前进一位。长度已经是 1 1 1 的那一截,没法再分开。

希望最后桌上正好摆着 K K K 截,各截长度分别是 B 1 , B 2 , ... , B K B_1,B_2,\dots,B_K B1,B2,...,BK。每一截都得是切出来的一整根,不能拿几截重新接上;桌上也不许多留任何一截。

请判断多多只靠这样切,能不能凑出这 K K K 截。

输入描述

首行给出整数 Q Q Q( 0 < Q ≤ 50 0 < Q \le 50 0<Q≤50),表示数据一共有几组。

每组占两行。前一行是两个整数 S , K S,K S,K( 1 ≤ S ≤ 10 14 , 1 ≤ K ≤ 10 5 1 \le S \le 10^{14},1 \le K \le 10^5 1≤S≤1014,1≤K≤105),依次表示绳子一开始有多长、想切成几截;后一行是 K K K 个整数 B 1 , B 2 , ... , B K B_1,B_2,\dots,B_K B1,B2,...,BK( 1 ≤ B i ≤ 10 9 1 \le B_i \le 10^9 1≤Bi≤109),依次表示每一截想要的长度。

输出描述

一共写出 Q Q Q 行。每一行只写 Y E S YES YES 或 N O NO NO,表示这一组能不能切成目标绳子。

样例1

输入

复制代码
3
7 3
2 2 3
6 3
2 2 2
9 2
4 6

输出

复制代码
YES
NO
NO

说明

  • 第一组:长度为 7 7 7 的绳子先分开成 3 3 3 与 4 4 4,再把长度为 4 4 4 的那截分开成 2 2 2 与 2 2 2,桌上就是 2 , 2 , 3 2,2,3 2,2,3。
  • 第二组:三截加起来等于 6 6 6,和一开始的长度一样,可是 6 6 6 只能先分开成 3 3 3 与 3 3 3;再动其中一截 3 3 3,只能得到 1 1 1 与 2 2 2,结果变成 3 , 1 , 2 3,1,2 3,1,2,永远变不成 2 , 2 , 2 2,2,2 2,2,2。
  • 第三组: 4 4 4 与 6 6 6 加起来是 10 10 10,并不是一开始的 9 9 9。切割改变不了各截长度之和,因此做不到。

题解

思路

解题算法:贪心

  1. 由于S最大为10^14,所以不能真的模拟切割过程,采用贪心 + 最大堆进行处理。
  2. 因为切割只能让绳子变短。如果当前最大的绳子都小于某个目标长度,那么这个目标长度就不可能再出现。所以每次优先切割当前最长的绳子,直到得到目标长度。
  3. 具体做法:
    • 计算所有目标长度总和sum, 如果sum !=S直接输出NO
    • 将所有目标长度放入一个最大堆
    • 将S放入另一个最大堆
    • 每次取出两个堆最大长度进行比较
      • 如果相等,说明找到一段目标绳子,两个堆顶元素弹出。
      • 如果当前绳子长度更大,就将它切成两段,把两段放回绳子堆
      • 如果目标长度更大,说明无法得到目标,输出NO
  4. 算法总体时间复杂度为O(NlogN)

C++

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

using ll = long long;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int Q;
    cin >> Q;

    while (Q--) {
        ll S, sum = 0;
        int K;
        cin >> S >> K;

        priority_queue<ll> rope, target;

        rope.push(S);

        for (int i = 0; i < K; i++) {
            ll b;
            cin >> b;
            sum += b;
            target.push(b);
        }

        if (sum != S) {
            cout << "NO\n";
            continue;
        }

        bool ok = true;

        while (!target.empty()) {
            if (rope.empty()) {
                ok = false;
                break;
            }

            ll x = rope.top();
            ll y = target.top();

            if (x < y) {
                ok = false;
                break;
            }

            if (x == y) {
                rope.pop();
                target.pop();
            } else {
                rope.pop();

                ll a = x / 2;
                ll b = x - a;

                if (a > 0) rope.push(a);
                if (b > 0) rope.push(b);
            }
        }

        cout << (ok ? "YES" : "NO") << '\n';
    }

    return 0;
}

java

java 复制代码
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int Q = sc.nextInt();

        while (Q-- > 0) {
            long S = sc.nextLong();
            int K = sc.nextInt();
            long sum = 0;

            // 最大堆,Java 默认是最小堆,使用 Collections.reverseOrder()
            PriorityQueue<Long> rope = new PriorityQueue<>(Collections.reverseOrder());
            PriorityQueue<Long> target = new PriorityQueue<>(Collections.reverseOrder());

            rope.offer(S);

            for (int i = 0; i < K; i++) {
                long b = sc.nextLong();
                sum += b;
                target.offer(b);
            }

            if (sum != S) {
                System.out.println("NO");
                continue;
            }

            boolean ok = true;

            while (!target.isEmpty()) {
                if (rope.isEmpty()) {
                    ok = false;
                    break;
                }

                long x = rope.peek();
                long y = target.peek();

                if (x < y) {
                    ok = false;
                    break;
                }

                if (x == y) {
                    rope.poll();
                    target.poll();
                } else {
                    rope.poll();

                    long a = x / 2;
                    long b = x - a;

                    if (a > 0) rope.offer(a);
                    if (b > 0) rope.offer(b);
                }
            }

            System.out.println(ok ? "YES" : "NO");
        }

        sc.close();
    }
}

python

python 复制代码
import heapq

Q = int(input())

for _ in range(Q):
    S, K = map(int, input().split())
    B = list(map(int, input().split()))

    # 使用负数模拟最大堆
    rope = [-S]
    target = [-b for b in B]
    heapq.heapify(target)

    if sum(B) != S:
        print("NO")
        continue

    ok = True

    while target:
        if not rope:
            ok = False
            break

        x = -rope[0]
        y = -target[0]

        if x < y:
            ok = False
            break

        if x == y:
            heapq.heappop(rope)
            heapq.heappop(target)
        else:
            heapq.heappop(rope)

            a = x // 2
            b = x - a

            if a > 0:
                heapq.heappush(rope, -a)
            if b > 0:
                heapq.heappush(rope, -b)

    print("YES" if ok else "NO")

Go

go 复制代码
package main

import (
	"bufio"
	"container/heap"
	"fmt"
	"os"
)

type MaxHeap []int64

func (h MaxHeap) Len() int {
	return len(h)
}

func (h MaxHeap) Less(i, j int) bool {
	return h[i] > h[j]
}

func (h MaxHeap) Swap(i, j int) {
	h[i], h[j] = h[j], h[i]
}

func (h *MaxHeap) Push(x interface{}) {
	*h = append(*h, x.(int64))
}

func (h *MaxHeap) Pop() interface{} {
	old := *h
	n := len(old)
	x := old[n-1]
	*h = old[:n-1]
	return x
}

func main() {
	reader := bufio.NewReader(os.Stdin)
	writer := bufio.NewWriter(os.Stdout)
	defer writer.Flush()

	var Q int
	fmt.Fscan(reader, &Q)

	for ; Q > 0; Q-- {
		var S int64
		var K int
		fmt.Fscan(reader, &S, &K)

		rope := &MaxHeap{}
		target := &MaxHeap{}
		heap.Init(rope)
		heap.Init(target)

		heap.Push(rope, S)

		var sum int64

		for i := 0; i < K; i++ {
			var b int64
			fmt.Fscan(reader, &b)
			sum += b
			heap.Push(target, b)
		}

		if sum != S {
			fmt.Fprintln(writer, "NO")
			continue
		}

		ok := true

		for target.Len() > 0 {
			if rope.Len() == 0 {
				ok = false
				break
			}

			x := (*rope)[0]
			y := (*target)[0]

			if x < y {
				ok = false
				break
			}

			if x == y {
				heap.Pop(rope)
				heap.Pop(target)
			} else {
				heap.Pop(rope)

				a := x / 2
				b := x - a

				if a > 0 {
					heap.Push(rope, a)
				}
				if b > 0 {
					heap.Push(rope, b)
				}
			}
		}

		if ok {
			fmt.Fprintln(writer, "YES")
		} else {
			fmt.Fprintln(writer, "NO")
		}
	}
}

javascript

js 复制代码
const readline = require('readline');

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

let input = [];

rl.on('line', line => {
    input.push(...line.trim().split(/\s+/).filter(Boolean));
});

rl.on('close', () => {
    let idx = 0;
    const Q = Number(input[idx++]);
    const ans = [];

    // 最大堆实现
    class MaxHeap {
        constructor() {
            this.heap = [];
        }

        size() {
            return this.heap.length;
        }

        peek() {
            return this.heap[0];
        }

        push(x) {
            const h = this.heap;
            h.push(x);
            let i = h.length - 1;

            while (i > 0) {
                const p = Math.floor((i - 1) / 2);
                if (h[p] >= h[i]) break;
                [h[p], h[i]] = [h[i], h[p]];
                i = p;
            }
        }

        pop() {
            const h = this.heap;
            const res = h[0];
            const last = h.pop();

            if (h.length > 0) {
                h[0] = last;
                let i = 0;

                while (true) {
                    let largest = i;
                    const l = i * 2 + 1;
                    const r = i * 2 + 2;

                    if (l < h.length && h[l] > h[largest]) {
                        largest = l;
                    }
                    if (r < h.length && h[r] > h[largest]) {
                        largest = r;
                    }
                    if (largest === i) break;

                    [h[i], h[largest]] = [h[largest], h[i]];
                    i = largest;
                }
            }

            return res;
        }
    }

    while (idx < input.length && ans.length < Q) {
        const S = Number(input[idx++]);
        const K = Number(input[idx++]);
        let sum = 0;

        const rope = new MaxHeap();
        const target = new MaxHeap();

        rope.push(S);

        for (let i = 0; i < K; i++) {
            const b = Number(input[idx++]);
            sum += b;
            target.push(b);
        }

        if (sum !== S) {
            ans.push("NO");
            continue;
        }

        let ok = true;

        while (target.size() > 0) {
            if (rope.size() === 0) {
                ok = false;
                break;
            }

            const x = rope.peek();
            const y = target.peek();

            if (x < y) {
                ok = false;
                break;
            }

            if (x === y) {
                rope.pop();
                target.pop();
            } else {
                rope.pop();

                const a = Math.floor(x / 2);
                const b = x - a;

                if (a > 0) rope.push(a);
                if (b > 0) rope.push(b);
            }
        }

        ans.push(ok ? "YES" : "NO");
    }

    console.log(ans.join('\n'));
});
相关推荐
无限码力5 小时前
拼多多校招笔试真题 10.26 -车厢调序耗电(C++/Py/Java /Js/Go)
pdd·拼多多笔试真题·拼多多技术岗笔试真题·拼多多校招笔试真题·拼多多技术岗校招笔试真题
无限码力3 天前
拼多多校招笔试真题 10.18 - 断缆两侧负荷积(C++/Py/Java /Js/Go)
pdd·拼多多校招笔试真题·拼多多秋招真题·拼多多研发岗真题·拼多多校招真题·拼多多校招研发岗笔试
无限码力4 天前
拼多多校招笔试真题 10.18 - 甲乙指示灯链(C++/Py/Java /Js/Go)
1024程序员节·pdd·拼多多笔试真题·拼多多技术岗笔试真题·拼多多秋招笔试真题·拼多多校招笔试真题
无限码力5 天前
拼多多校招笔试真题 10.18 - 叠放库位计数(C++/Py/Java /Js/Go)
拼多多笔试真题·拼多多技术岗笔试真题·拼多多秋招笔试真题·拼多多校招笔试真题·pdd笔试
无限码力9 天前
拼多多笔试真题 10.11 - 测温共值最长段(C++/Py/Java /Js/Go)
pdd·拼多多笔试真题·拼多多技术岗笔试真题·拼多多秋招笔试真题·拼多多校招笔试真题
无限码力1 个月前
拼多多笔试真题 - 班次连窗日均(C++/Py/Java /Js/Go)
pdd·拼多多笔试真题·拼多多笔试题目题解·拼多多题库·拼多多机试真题
无限码力1 个月前
拼多多笔试真题 9.6 - 看旗派舟(C++/Py/Java /Js/Go)
pdd·拼多多笔试真题·拼多多笔试·拼多多笔试真题题解·拼多多9月6号笔试真题
无限码力1 个月前
拼多多笔试真题 9.6 - 限次罐笼(C++/Py/Java /Js/Go)
pdd·拼多多笔试真题·拼多多笔试真题题解·拼多多笔试题解·拼多多9月6号笔试真题
无限码力2 个月前
2026-8-30拼多多笔试真题-哪个查阅窗能留空(C++/Py/Java /Js/Go)
算法·pdd·pdd笔试真题·拼多多春招笔试真题·拼多多秋招笔试真题·拼多多笔试真题题解·拼多多笔试题解