拼多多笔试真题 - 班次连窗日均(C++/Py/Java /Js/Go)

班次连窗日均

拼多多 9月13号 笔试真题 第二题

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

题目内容

推理集群连续跑了 m m m 个班次,第 p p p 个班次的净值记为 v p v_p vp(可以为负,表示当班调度损耗)。要在班次序列上截取一段连续窗口 q , s q,s q,s,窗口长度必须至少为 w w w,否则调度系统不认这段窗口。

窗口的班均净值定义为

⌊ v q + v q + 1 + ⋯ + v s s − q + 1 ⌋ \left\lfloor \frac{v_q + v_{q+1} + \dots + v_s}{s-q+1} \right\rfloor ⌊s−q+1vq+vq+1+⋯+vs⌋

其中 ⌊ ⋅ ⌋ \lfloor \cdot \rfloor ⌊⋅⌋ 表示不超过该实数的最大整数,例如 ⌊ − 11 / 2 ⌋ = ⌊ − 5.5 ⌋ = − 6 \lfloor -11/2 \rfloor = \lfloor -5.5 \rfloor = -6 ⌊−11/2⌋=⌊−5.5⌋=−6。

请在所有长度合法的窗口里,把班均净值做到最大,并输出这个最大值。保证 w ≤ m w \le m w≤m,因此至少存在一个合法窗口。

输入描述

首行给出整数 g g g( 1 ≤ g ≤ 10 1\le g\le 10 1≤g≤10),表示随后有多少组数据。

每一组的格式如下:

该组开头给出整数 m m m( 1 ≤ m ≤ 10 5 1\le m\le 10^5 1≤m≤105),即班次个数。

下一行给出整数 w w w( 1 ≤ w ≤ m 1\le w\le m 1≤w≤m),即窗口最短长度。

第三行 m m m 个整数 v 1 , v 2 , ... , v m v_1,v_2,\dots,v_m v1,v2,...,vm( ∣ v p ∣ ≤ 10 9 |v_p|\le 10^9 ∣vp∣≤109),用逗号分隔,依次为各班次净值。

输出描述

输出一行,包含 g g g 个整数,相邻两项以空格分隔,依次为每一组的最大班均净值。

样例1

输入

复制代码
3
6
2
4,-1,8,-6,3,5
3
2
-2,-9,-4
4
4
10,-1,-1,10

输出

复制代码
4 -5 4

说明

第一组最短长度为 2 2 2,取最后两个班次 { 3 , 5 } \{3,5\} {3,5},和为 8 8 8,班均为 ⌊ 8 / 2 ⌋ = 4 \lfloor 8/2 \rfloor = 4 ⌊8/2⌋=4。更长的窗口都到不了 4 4 4。

第二组全是亏损。取整段 { − 2 , − 9 , − 4 } \{-2,-9,-4\} {−2,−9,−4},和为 − 15 -15 −15,班均为 ⌊ − 15 / 3 ⌋ = − 5 \lfloor -15/3 \rfloor = -5 ⌊−15/3⌋=−5。只取 { − 2 , − 9 } \{-2,-9\} {−2,−9} 得到 ⌊ − 11 / 2 ⌋ = − 6 \lfloor -11/2 \rfloor = -6 ⌊−11/2⌋=−6,更差。

第三组最短长度等于班次数,只能取整段,和为 18 18 18,班均为 ⌊ 18 / 4 ⌋ = 4 \lfloor 18/4 \rfloor = 4 ⌊18/4⌋=4。

题解

思路

解题算法:二分 + 前缀和

  1. 二分最大班均净值mid,使用前缀和判断是否存在长度至少为w的子数组,使平均值 ≥ mid。
    • 存在: left = mid + 1
    • 不存在: right = mid - 1
  2. 判断是否存在长度至少为w的子数组,使平均值 ≥ mid,可以将每个数变为ai = vi - x,问题变为是否存在一个长度至少为 w 的连续子数组,满足元素和 >= 0?使用前缀和判断是否存在prefix[j] - prefix[i] >=0,其中j - i >= w
  3. 算法总体时间复杂度为O(mlog10^9)

C++

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

// 判断是否存在长度至少为 w 的窗口,使平均值 >= x
bool check(const vector<ll>& v, int w, ll x) {
    int m = v.size();

    vector<ll> prefix(m + 1, 0);

    for (int i = 1; i <= m; i++) {
        prefix[i] = prefix[i - 1] + v[i - 1] - x;
    }

    ll minPrefix = 0;

    for (int i = w; i <= m; i++) {
        // j <= i - w
        minPrefix = min(minPrefix, prefix[i - w]);

        // prefix[i] - prefix[j] >= 0
        if (prefix[i] >= minPrefix) {
            return true;
        }
    }

    return false;
}

ll solve(int m, int w, vector<ll>& v) {
    ll left = -1000000000;
    ll right = 1000000000;
    while (left <= right) {
        ll mid = left + (right - left) / 2;

        if (check(v, w, mid)) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    return right;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); 
    int g;
    cin >> g;
    vector<ll> ans;
    while (g--) {
        int m, w;
        cin >> m;
        cin >> w;
        vector<ll> v(m);
        for (int i = 0; i < m; i++) {
            char comma;
            cin >> v[i];
            if (i + 1 < m) {
                cin >> comma;
            }
        }
        ans.push_back(solve(m, w, v));
    }
    
    for (int i = 0; i < ans.size(); i++) {
        if (i > 0) {
            cout << " ";
        }
        cout << ans[i];
    }
    return 0;
}

java

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

public class Main {

    // 判断是否存在长度至少为 w 的窗口,使平均值 >= x
    static boolean check(long[] v, int w, long x) {
        int m = v.length;

        long[] prefix = new long[m + 1];

        for (int i = 1; i <= m; i++) {
            prefix[i] = prefix[i - 1] + v[i - 1] - x;
        }

        long minPrefix = 0;

        for (int i = w; i <= m; i++) {
            // j <= i - w
            minPrefix = Math.min(minPrefix, prefix[i - w]);

            // prefix[i] - prefix[j] >= 0
            if (prefix[i] >= minPrefix) {
                return true;
            }
        }

        return false;
    }

    static long solve(int m, int w, long[] v) {
        long left = -1000000000L;
        long right = 1000000000L;

        while (left <= right) {
            long mid = left + (right - left) / 2;

            if (check(v, w, mid)) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }

        return right;
    }

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

        int g = sc.nextInt();
        long[] ans = new long[g];

        for (int t = 0; t < g; t++) {
            int m = sc.nextInt();
            int w = sc.nextInt();

            String[] parts = sc.next().split(",");

            long[] v = new long[m];

            for (int i = 0; i < m; i++) {
                v[i] = Long.parseLong(parts[i]);
            }

            ans[t] = solve(m, w, v);
        }

        for (int i = 0; i < g; i++) {
            if (i > 0) {
                System.out.print(" ");
            }
            System.out.print(ans[i]);
        }
    }
}

python

python 复制代码
import sys


# 判断是否存在长度至少为 w 的窗口,使平均值 >= x
def check(v, w, x):
    m = len(v)

    prefix = [0] * (m + 1)

    for i in range(1, m + 1):
        prefix[i] = prefix[i - 1] + v[i - 1] - x

    min_prefix = 0

    for i in range(w, m + 1):
        # j <= i - w
        min_prefix = min(min_prefix, prefix[i - w])

        # prefix[i] - prefix[j] >= 0
        if prefix[i] >= min_prefix:
            return True

    return False


def solve(m, w, v):
    left = -1000000000
    right = 1000000000

    while left <= right:
        mid = left + (right - left) // 2

        if check(v, w, mid):
            left = mid + 1
        else:
            right = mid - 1

    return right


def main():
    input = sys.stdin.readline

    g = int(input())

    ans = []

    for _ in range(g):
        m = int(input())
        w = int(input())

        v = list(map(int, input().strip().split(",")))

        ans.append(solve(m, w, v))

    print(*ans)


if __name__ == "__main__":
    main()

javascript

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

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

const lines = [];

rl.on('line', line => {
    lines.push(line.trim());
});

rl.on('close', () => {
    let index = 0;

    // 判断是否存在长度至少为 w 的窗口,使平均值 >= x
    function check(v, w, x) {
        const m = v.length;

        const prefix = new Array(m + 1).fill(0);

        for (let i = 1; i <= m; i++) {
            prefix[i] = prefix[i - 1] + v[i - 1] - x;
        }

        let minPrefix = 0;

        for (let i = w; i <= m; i++) {
            // j <= i - w
            minPrefix = Math.min(minPrefix, prefix[i - w]);

            // prefix[i] - prefix[j] >= 0
            if (prefix[i] >= minPrefix) {
                return true;
            }
        }

        return false;
    }

    function solve(m, w, v) {
        let left = -1000000000;
        let right = 1000000000;

        while (left <= right) {
            const mid = Math.floor(left + (right - left) / 2);

            if (check(v, w, mid)) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }

        return right;
    }

    const g = parseInt(lines[index++]);
    const ans = [];

    for (let t = 0; t < g; t++) {
        const m = parseInt(lines[index++]);
        const w = parseInt(lines[index++]);

        const v = lines[index++].split(',').map(Number);

        ans.push(solve(m, w, v));
    }

    console.log(ans.join(' '));
});

Go

go 复制代码
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

// 判断是否存在长度至少为 w 的窗口,使平均值 >= x
func check(v []int64, w int, x int64) bool {
	m := len(v)

	prefix := make([]int64, m+1)

	for i := 1; i <= m; i++ {
		prefix[i] = prefix[i-1] + v[i-1] - x
	}

	var minPrefix int64 = 0

	for i := w; i <= m; i++ {
		// j <= i - w
		if prefix[i-w] < minPrefix {
			minPrefix = prefix[i-w]
		}

		// prefix[i] - prefix[j] >= 0
		if prefix[i] >= minPrefix {
			return true
		}
	}

	return false
}

func solve(m int, w int, v []int64) int64 {
	var left int64 = -1000000000
	var right int64 = 1000000000

	for left <= right {
		mid := left + (right-left)/2

		if check(v, w, mid) {
			left = mid + 1
		} else {
			right = mid - 1
		}
	}

	return right
}

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

	// 读取所有非空行
	lines := make([]string, 0)

	for {
		line, err := in.ReadString('\n')

		line = strings.TrimSpace(line)

		if line != "" {
			lines = append(lines, line)
		}

		if err != nil {
			break
		}
	}

	index := 0

	// 第一行是测试组数
	g, _ := strconv.Atoi(lines[index])
	index++

	ans := make([]int64, g)

	for t := 0; t < g; t++ {
		// 第一行:m
		m, _ := strconv.Atoi(lines[index])
		index++

		// 第二行:w
		w, _ := strconv.Atoi(lines[index])
		index++

		// 第三行:数组
		parts := strings.Split(lines[index], ",")
		index++

		v := make([]int64, m)

		for i := 0; i < m; i++ {
			v[i], _ = strconv.ParseInt(strings.TrimSpace(parts[i]), 10, 64)
		}

		ans[t] = solve(m, w, v)
	}

	for i := 0; i < g; i++ {
		if i > 0 {
			fmt.Fprint(out, " ")
		}
		fmt.Fprint(out, ans[i])
	}
}
相关推荐
无限码力15 小时前
拼多多笔试真题题解 - 并箱放行(C++/Py/Java /Js/Go)
拼多多·拼多多笔试真题·拼多多笔试题解·拼多多9月6号笔试真题
无限码力1 天前
拼多多笔试真题 9.6 - 看旗派舟(C++/Py/Java /Js/Go)
pdd·拼多多笔试真题·拼多多笔试·拼多多笔试真题题解·拼多多9月6号笔试真题
无限码力1 天前
拼多多笔试真题 9.6 - 限次罐笼(C++/Py/Java /Js/Go)
pdd·拼多多笔试真题·拼多多笔试真题题解·拼多多笔试题解·拼多多9月6号笔试真题
无限码力13 天前
2026-8-30拼多多笔试真题-哪个查阅窗能留空(C++/Py/Java /Js/Go)
算法·pdd·pdd笔试真题·拼多多春招笔试真题·拼多多秋招笔试真题·拼多多笔试真题题解·拼多多笔试题解
无限码力16 天前
pdd笔试真题-和差方程最少标定(C++/Py/Java /Js/Go)
pdd·拼多多笔试真题·pdd笔试真题·拼多多技术岗笔试真题·拼多多秋招笔试·拼多多笔试题解
无限码力17 天前
pdd笔试真题-驿站补给最短耗时(C++/Py/Java /Js/Go)
pdd·拼多多笔试真题·拼多多机试·拼多多技术岗笔试·pdd笔试真题·拼多多技术岗笔试真题·pdd笔试真题题解
无限码力1 个月前
拼多多笔试真题-评价展示序列(C++/Py/Java /Js/Go)
拼多多·pdd·拼多多机试·拼多多技术岗笔试·拼多多笔试·拼多多技术岗笔试真题
无限码力1 个月前
拼多多笔试真题-多多送快递(C++/Py/Java /Js/Go)
拼多多·pdd·拼多多笔试真题·拼多多机试·拼多多笔试·拼多多技术岗真题
无限码力1 个月前
拼多多笔试真题-多多的告警网络(C++/Py/Java /Js/Go)
拼多多·pdd·拼多多笔试真题·拼多多笔试·拼多多技术岗笔试真题