叠放库位计数
拼多多 10月18号 笔试真题 第二题
拼多多真题目录点击查看: 拼多多笔试真题题库目录|笔试题库 + 算法考点详解
题目内容
仓储区的货架沿直线编号,每个编号对应一个库位,编号都是正整数。每张送货单会占住其中连续的一段,段的两头两个库位都要算进去。
给出一个门槛。请算出有多少个库位,被不少于这么多张送货单同时占住。
输入描述
第一行一个整数 t t t,表示门槛。
第二行一个整数 m m m,表示送货单张数。
后面再给出 m m m 行记录。每一行先写右端库位 b b b,再写左端库位 a a a。
1 ≤ m ≤ 10 5 1 \le m \le 10^5 1≤m≤105
1 ≤ t ≤ 10 9 1 \le t \le 10^9 1≤t≤109
1 ≤ a ≤ b ≤ 10 9 1 \le a \le b \le 10^9 1≤a≤b≤109
输出描述
输出一个整数,表示叠放次数达到门槛的库位个数。
样例1
输入
2
3
6 2
8 4
9 5
输出
5
说明
三张单分别占住 2 , 6 2,6 2,6、 4 , 8 4,8 4,8、 5 , 9 5,9 5,9。库位 4 4 4 到 8 8 8 的叠放次数都不低于 2 2 2,一共 5 5 5 个。库位 2 2 2、 3 3 3、 9 9 9 都只有一张单。
样例2
输入
1
3
2 1
6 5
10 8
输出
7
说明
三段分别是 1 , 2 1,2 1,2、 5 , 6 5,6 5,6、 8 , 10 8,10 8,10,彼此隔开。门槛为 1 1 1 时,这 2 + 2 + 3 = 7 2+2+3=7 2+2+3=7 个库位都要计入。
样例3
输入
4
2
8 3
8 3
输出
0
说明
两张单占的是同一段 3 , 8 3,8 3,8,任一库位最多被 2 2 2 张单占住,达不到门槛 4 4 4。
题解
思路
解题算法:差分 + 排序
- 因为每张送货单覆盖的是连续区间
[a,b],由于题目给出的区间范围,不能直接开10^9的数组会爆内存,我们可以记录区间的变化位置,不需要逐个库位处理。 - 对于一个区间
[a,b],在差分中记录:- 位置a,覆盖次数+1
- 位置b+1,覆盖次数-1
- 然后对变化记录按照位置排序,然后从前往后进行扫描,统计相邻两个变化点之间有多少个库位满足覆盖次数不少于
t。 - 算法时间复杂度为
O(mlogm)
C++
cpp
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
ll t;
int m;
cin >> t >> m;
vector<pair<ll, int>> events;
events.reserve(2 * m);
for (int i = 0; i < m; i++) {
ll b, a;
cin >> b >> a;
events.push_back({a, 1});
events.push_back({b + 1, -1});
}
sort(events.begin(), events.end());
ll ans = 0;
ll cover = 0;
ll prev = events[0].first;
int i = 0;
while (i < (int)events.size()) {
ll pos = events[i].first;
// [prev, pos - 1] 这一段的覆盖次数为 cover
if (cover >= t) {
ans += pos - prev;
}
// 合并同一个位置的所有变化
while (i < (int)events.size() && events[i].first == pos) {
cover += events[i].second;
i++;
}
prev = pos;
}
cout << ans << '\n';
return 0;
}
java
java
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
long t = sc.nextLong();
int m = sc.nextInt();
List<long[]> events = new ArrayList<>();
for (int i = 0; i < m; i++) {
long b = sc.nextLong();
long a = sc.nextLong();
events.add(new long[]{a, 1});
events.add(new long[]{b + 1, -1});
}
events.sort((x, y) -> Long.compare(x[0], y[0]));
long ans = 0;
long cover = 0;
long prev = events.get(0)[0];
int i = 0;
while (i < events.size()) {
long pos = events.get(i)[0];
// [prev, pos - 1] 这一段的覆盖次数为 cover
if (cover >= t) {
ans += pos - prev;
}
// 合并同一个位置的所有变化
while (i < events.size() && events.get(i)[0] == pos) {
cover += events.get(i)[1];
i++;
}
prev = pos;
}
System.out.println(ans);
sc.close();
}
}
python
python
import sys
input = sys.stdin.readline
t = int(input())
m = int(input())
events = []
for _ in range(m):
b, a = map(int, input().split())
events.append((a, 1))
events.append((b + 1, -1))
events.sort()
ans = 0
cover = 0
prev = events[0][0]
i = 0
while i < len(events):
pos = events[i][0]
# [prev, pos - 1] 这一段的覆盖次数为 cover
if cover >= t:
ans += pos - prev
# 合并同一个位置的所有变化
while i < len(events) and events[i][0] == pos:
cover += events[i][1]
i += 1
prev = pos
print(ans)
Go
go
package main
import (
"bufio"
"fmt"
"os"
"sort"
)
type Event struct {
pos int64
delta int
}
func main() {
reader := bufio.NewReader(os.Stdin)
writer := bufio.NewWriter(os.Stdout)
defer writer.Flush()
var t int64
var m int
fmt.Fscan(reader, &t, &m)
events := make([]Event, 0, 2*m)
for i := 0; i < m; i++ {
var b, a int64
fmt.Fscan(reader, &b, &a)
events = append(events, Event{a, 1})
events = append(events, Event{b + 1, -1})
}
sort.Slice(events, func(i, j int) bool {
return events[i].pos < events[j].pos
})
var ans int64 = 0
var cover int64 = 0
prev := events[0].pos
i := 0
for i < len(events) {
pos := events[i].pos
// [prev, pos - 1] 这一段的覆盖次数为 cover
if cover >= t {
ans += pos - prev
}
// 合并同一个位置的所有变化
for i < len(events) && events[i].pos == pos {
cover += int64(events[i].delta)
i++
}
prev = pos
}
fmt.Fprintln(writer, ans)
}
javascript
js
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const input = [];
rl.on('line', line => {
input.push(line.trim());
});
rl.on('close', () => {
let idx = 0;
const t = Number(input[idx++]);
const m = Number(input[idx++]);
const events = [];
for (let i = 0; i < m; i++) {
const [b, a] = input[idx++].split(' ').map(Number);
events.push([a, 1]);
events.push([b + 1, -1]);
}
events.sort((x, y) => x[0] - y[0]);
let ans = 0;
let cover = 0;
let prev = events[0][0];
let i = 0;
while (i < events.length) {
const pos = events[i][0];
// [prev, pos - 1] 这一段的覆盖次数为 cover
if (cover >= t) {
ans += pos - prev;
}
// 合并同一个位置的所有变化
while (i < events.length && events[i][0] === pos) {
cover += events[i][1];
i++;
}
prev = pos;
}
console.log(ans);
});