在线评测链接:P1309
塔子哥面临一个挑战,需要从海量的网络数据中筛选出繁忙时段的数据。考虑到数据规模庞大,塔子哥无法对所有数据进行排序,然后选择前 N N N个最大值作为繁忙时段的数据。聪明的塔子哥想到了使用一个固定大小的优先级队列来筛选数据。为了简化场景,我们将海量网络数据表示为一个正整数集合,并且仅需选择 N N N个最大的正整数作为结果。对于每批输入数据,塔子哥将输出一行结果,将这 N N N个正整数按照顺序拼接成一行字符串进行输出。
输入第一行为正整数 N N N和 M M M, N N N为忙时个数, M M M为输入的数据行数,( 1 1 1 ≤ \leq ≤ N N N ≤ \leq ≤ 24 24 24 , 1 1 1 ≤ \leq ≤ M M M ≤ \leq ≤ 1000 1000 1000)
接下来输入 M M M行,每行两个正整数 A , B A,B A,B,以空格分隔,表示有 A A A个重复的正整数 B B B, 1 1 1 ≤ \leq ≤ A A A, B B B ≤ \leq ≤ 2147483647 2147483647 2147483647 。
输出每增加一批数据对应的队列结果,直接将队列里的所有数据集从大到小拼接成字符串输出.
输入
24 3
11 5
2 1
18 7
输出
55555555555
5555555555511
777777777777777777555555
解释
保留 24 24 24个忙时数据
第一次输入 11 11 11个 5 5 5,则队列输出为 55555555555 55555555555 55555555555
第二次输入 2 2 2个 1 1 1,则队列输出为 5555555555511 5555555555511 5555555555511
第三次输入 18 18 18个 7 7 7,则队列输出为 777777777777777777555555 777777777777777777555555 777777777777777777555555
给定 M M M 个数据,每个数据为 A A A 个重复的 B B B 。要求每读入一次数据,最多输出当前已读数据中最大的 N N N 个值。
为了能够快速得到最大的值,我们可以使用大根堆来对数据进行存储。
什么是大根堆?
其学名是优先队列。具体表现形式(或者说我们自己手动模拟的形式)是一颗二叉树,每个结点最多有两个儿子,且对于任意一个结点,都符合:该结点任意儿子的值,都比该结点的值小。因此,堆顶(或者说二叉树的根节点)就是所有数中最大的值。
对于C++
选手来说,刚好有STL
能够使用,即priority_queue
,其默认是大根堆。比较基础的几个函数分别是:
pop()
,弹出堆顶,并返回该元素push(x)
,将 x x x 加入到堆中size()
,返回堆中当前元素的个数clear()
,清空堆其他语言也有相应的封装包,比如python
里有heapq
。因此如果自己不想动手实现一个优先队列的话,可以直接使用封装包。
由于该题的数据量很小,我们可以直接借助大根堆来模拟这个过程。
具体过程如下:
q
中tmp
中,直到输出一共 N N N 个数字tmp
中的数据再重新放回堆中由于 N N N 很小,最大仅为24,也就是说每次最多输出24个字符,而堆的每次操作都可以近似看作 O ( l o g M ) O(logM) O(logM) 的,最坏情况下每次取出堆中24个数据(每个数据只重复1次)输出再放回去也就是 O ( N l o g M ) O(NlogM) O(NlogM) 的时间复杂度。读入 M M M 行数据,总共要输出 M M M 次,因此总时间复杂度为 O ( N M l o g M ) O(NMlogM) O(NMlogM)。
#include
#include
#include
using namespace std;
int n,m;
struct node{
int cnt;// 重复多少次
int val;// 值
};
queue tmp;
priority_queue q;
bool operator <(const node a,const node b){// 重载运算符
return a.val0){
if(!q.size()) break;// 大根堆里已经没有字符了,直接break
// 取出堆顶
a=q.top();
q.pop();
// 输出 min(rest,a.cnt) 次
for(int i=1;i<=min(rest,a.cnt);++i){
printf("%d",a.val);
}
// 从堆里取出来放到临时队列中
tmp.push(a);
rest-=a.cnt;
}
while(tmp.size()){// 将队列中的数据重新放回堆中
q.push(tmp.front());
tmp.pop();
}
printf("\n");
}
return 0;
}
import heapq
class Node:
def __init__(self, cnt, val):
self.cnt = cnt
self.val = val
def __lt__(self, other):
return self.val < other.val
n, m = map(int, input().split())
q = []
tmp = []
for _ in range(m):
cnt, val = map(int, input().split())
heapq.heappush(q, Node(cnt, val))
rest = n # rest为输出某一字符后,剩余的长度,初始为n
while rest > 0:
if not q:
break # 大根堆里已经没有字符了,直接break
# 取出堆顶
a = heapq.heappop(q)
# 输出 min(rest,a.cnt) 次
for _ in range(min(rest, a.cnt)):
print(a.val, end="")
# 从堆里取出来放到临时队列中
tmp.append(a)
rest -= a.cnt
while tmp:
# 将队列中的数据重新放回堆中
heapq.heappush(q, tmp.pop(0))
print()
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Scanner;
class Main {
static class Node implements Comparable<Node> {
int cnt; // 重复多少次
int val; // 值
public Node(int cnt, int val) {
this.cnt = cnt;
this.val = val;
}
@Override
public int compareTo(Node other) {
return Integer.compare(this.val, other.val);
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = scanner.nextInt();
Queue<Node> q = new PriorityQueue<>();
Queue<Node> tmp = new PriorityQueue<>();
for (int i = 0; i < m; i++) {
int cnt = scanner.nextInt();
int val = scanner.nextInt();
q.offer(new Node(cnt, val));
int rest = n; // rest为输出某一字符后,剩余的长度,初始为n
while (rest > 0) {
if (q.isEmpty()) break; // 大根堆里已经没有字符了,直接break
// 取出堆顶
Node a = q.poll();
// 输出 min(rest,a.cnt) 次
for (int j = 0; j < Math.min(rest, a.cnt); j++) {
System.out.print(a.val);
}
// 从堆里取出来放到临时队列中
tmp.offer(a);
rest -= a.cnt;
}
while (!tmp.isEmpty()) {
// 将队列中的数据重新放回堆中
q.offer(tmp.poll());
}
System.out.println();
}
}
}
package main
import (
"container/heap"
"fmt"
)
type Node struct {
cnt int // 重复多少次
val int // 值
}
type PriorityQueue []Node
func (pq PriorityQueue) Len() int { return len(pq) }
func (pq PriorityQueue) Less(i, j int) bool {
return pq[i].val < pq[j].val
}
func (pq PriorityQueue) Swap(i, j int) {
pq[i], pq[j] = pq[j], pq[i]
}
func (pq *PriorityQueue) Push(x interface{}) {
item := x.(Node)
*pq = append(*pq, item)
}
func (pq *PriorityQueue) Pop() interface{} {
old := *pq
n := len(old)
item := old[n-1]
*pq = old[0 : n-1]
return item
}
func main() {
var n, m int
fmt.Scan(&n, &m)
q := make(PriorityQueue, 0)
tmp := make(PriorityQueue, 0)
for i := 0; i < m; i++ {
var a Node
fmt.Scan(&a.cnt, &a.val)
heap.Push(&q, a)
rest := n // rest为输出某一字符后,剩余的长度,初始为n
for rest > 0 {
if len(q) == 0 {
break // 大根堆里已经没有字符了,直接break
}
// 取出堆顶
a := heap.Pop(&q).(Node)
// 输出 min(rest,a.cnt) 次
for j := 0; j < min(rest, a.cnt); j++ {
fmt.Print(a.val)
}
// 从堆里取出来放到临时队列中
heap.Push(&tmp, a)
rest -= a.cnt
}
for len(tmp) > 0 {
// 将队列中的数据重新放回堆中
heap.Push(&q, heap.Pop(&tmp).(Node))
}
fmt.Println()
}
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
const readline = require('readline');
function min(a, b) {
return a < b ? a : b;
}
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
let n, m;
const q = [];
const tmp = [];
rl.on('line', (line) => {
const input = line.split(' ').map(Number);
if (!n) {
[n, m] = input;
return;
}
const [cnt, val] = input;
q.push({ cnt, val });
let rest = n; // rest为输出某一字符后,剩余的长度,初始为n
while (rest > 0) {
if (q.length === 0) break; // 大根堆里已经没有字符了,直接break
// 取出堆顶
const a = q.shift();
// 输出 min(rest,a.cnt) 次
for (let i = 0; i < min(rest, a.cnt); i++) {
process.stdout.write(String(a.val));
}
// 从堆里取出来放到临时队列中
tmp.push(a);
rest -= a.cnt;
}
while (tmp.length > 0) {
// 将队列中的数据重新放回堆中
q.push(tmp.shift());
}
process.stdout.write('\n');
});