「题解」「STL」上网统计、有序表的最小和、桐桐的新闻系统、 查字典、Let the Balloon Rise、题海战之一

一、STL

STL是Standard Template Library的简称,中文名标准模板库,惠普实验室开发的一系列软件的统称。(查自度娘)

二、vector

1. 声明

#include 
using namespace std;
vector name;

2. 函数

push_back(x);
将x放于数组末尾
size();
返回数组个数
pop_back();
删除数组末元素
clear();
清除数组
insert(index,x);
在迭代器index后加入元素x
eraser(index);
删除数组中的元素,有两种用法,一是erase(it),删除迭代器it处的单个元素;二是erase(first, last),删除左闭右开区间[first, last)内的所有元素

3. 应用之上网统计

题目描述

在一个网络系统中有N个用户1≤N≤1000、M次上网记录1≤M≤5000。每个用户可以自己注册一个用户名,每个用户名是一个只含小写字母的字符串。每个上网的账号每次上网都会浏览网页,网页名是一串只含小写字母的字符串,每次上网日志都会留下记录,现在请你统计一次上网日志中,每个用户浏览了多少个网页。(输出按照输入顺序输出)

输入格式

第一行N和M 第2行到第M+1行为M条上网日志,每行两个字符串,用空格隔开

输出格式

N个ID的上网记录,具体看样例

样例

 样例输入

5 7
guomao wangyi
lifan tengxun
zhoushijian souhu
zhangshilin tengxun
guomao souhu
zhoushijian wangyi
liuyang bilibili

 样例输出

guomao wangyi souhu
lifan tengxun
zhoushijian souhu wangyi
zhangshilin tengxun
liuyang bilibili

分析

这道题我们定义一个结构体数组,储存每个用户的信息,每输入一个有两种操作,如果用户中没有此人,则将其压入数组中,如果有此人信息,则将网址存入用户信息里

代码
#include 
#include 
#include 
using namespace std;

const int M = 2e3 + 5;
int m, n;

struct user{
	string id;
	vector <string> web;
}a[M];

int used(string x) {
	for(int i = 1; i <= m; i ++) {
		if(a[i].id == x) {
			return i;
		}
	}
	return -1;
}

int main() {
	scanf("%d %d", &m, &n);
	m = 0;
	for(int i = 1; i <= n; i ++) {
		string name, new_web;
		cin >> name >> new_web;
		int k = used(name);
		if(k == -1) {
			a[++ m].web.clear();
			a[m].id = name;
			a[m].web.push_back(new_web);
		}
		else {
			a[k].web.push_back(new_web);
		}
	}
	for(int i = 1; i <= m; i ++) {
		cout << a[i].id << " ";
		for(vector<string>::iterator it = a[i].web.begin(); it != a[i].web.end(); ++ it) {
			cout << * it << " ";
		}
		puts("");
	}
	return 0;
}

4. 应用之查字典

题目描述

gm英语非常不好,为了应对全国英文四级考试,他手里有一本英语字典,现在有很多单词要查。请编写程序帮助他快速找到要查的单词所在的页码。

输入格式

第一行1个整数N,N≤10000,表示字典中一共有多少单词。
接下来每两行1个单词,其中:第一行是长度≤100的字符串,表示这个单词,全是小写字母,单词不会重复。 第二行是1个整数,表示这个单词在字典中的页码。
接下来是一个整数M,M≤N,表示要查的单词数。 接下来M行,每行一个字符串,表示要查的单词,保证在字典中存在。

输出格式

M行,每行1个整数,表示第i个单词在字典中的页码。

样例

 样例输入

2
scan
10
word
15
2
scan
word

 样例输出

10
15

分析

这道题一看就知道是一道水题经典的vector(可以用map做,这里展示vector代码)题,我们只需要定义结构体包含单词的拼写和页码即可,最后再O(n)访问就A了

代码
#include 
#include 
#include 
using namespace std;

struct word{
	string spelling;
	int page;
};

vector <word> a;

int main() {
	int t;
	scanf("%d", &t);
	for(; t > 0; t --) {
		word newest;
		cin >> newest.spelling >> newest.page;
		a.push_back(newest);
	}
	int tt;
	scanf("%d", &tt);
	for(; tt > 0; tt --) {
		string new_word;
		cin >> new_word;
		for(vector<word>::iterator it = a.begin(); it != a.end(); it ++) {
			if((*it).spelling == new_word) {
				cout << (*it).page << endl;
			}
		}
	}
	return 0;
} 

三、优先队列

1. 声明

#include
using namespace std;
priority_queue name;

2. 函数

push(x);
将x压入优先队列
top();
返回队首元素
pop();
弹出队首元素
empty();
返回队中元素个数

3. 应用之有序表的最小和

题目描述

给出两个长度为 n 的有序表 A 和 B,在 A 和 B 中各任取一个元素,可以得到 n*n 个和,求这些和中最小的 n 个。

输入格式

第 1 行包含 1 个整数正 n(n≤400000)。 第 2 行与第 3 行分别有 n 个整数,各代表有序表 A 和 B。一行中的每两个整数之间用一个空格隔开,大小在长整型范围内,数据保证有序表单调递增。

输出格式

输出共 n 行,每行一个整数,第 i 行为第 i 小的和。 数据保证在 long long 范围内。

样例

 【输入样例】

3
1 2 5
2 4 7

 【输出样例】

3
4
5

分析

我们来分析一下下面的数据:

A[1]+B[1] ≤ A[1]+B[2] ≤ A[1]+B[3] ≤ ······
A[2]+B[1] ≤ A[2]+B[2] ≤ A[2]+B[3] ≤ ······
······
A[n]+B[1] ≤ A[n]+B[2] ≤ A[n]+B[3] ≤ ······

显然,每一行的第一项和都是该行最小的和,我们不妨把每一行的第一项和(共n项)先压入优先队列,取出堆顶元素(最小值)并输出,如果取的是第i行的元素,就把第i行的下一个元素压入,让堆中始终保持n个元素和。

代码
#include 
#include 
#include 
using namespace std;

const int M = 4e5 + 5;
int a[M], b[M], p[M];

struct point{
	int k, num;
	bool operator<(const point x) const {
		return num > x.num;
	}
};
priority_queue<point> q;

int main() {
	int n;
	scanf("%d", &n);
	for(int i = 1; i <= n; i ++) {
		scanf("%d", &a[i]);
	}
	for(int i = 1; i <= n; i ++) {
		scanf("%d", &b[i]);
	}
	for(int i = 1; i <= n; i ++) {
		p[i] = 2;
		point temp;
		temp.num = a[i] + b[1];
		temp.k = i;
		q.push(temp);
	}
	for(int i = 1; i < n; i ++) {
		point pmet = q.top();
		q.pop();
		printf("%d", pmet.num);
		puts("");
		pmet.num = a[pmet.k] + b[p[pmet.k] ++];
		q.push(pmet);
	}
	point pmet = q.top();
	q.pop();
	printf("%d", pmet.num);
	return 0;
}

4. 应用之桐桐的新闻系统

题目描述

桐桐为期末的计算机作业设计了一套新闻系统,他把这套系统称为Argus。
使用这套系统的用户可以向这套系统注册,然后这套系统就会以用户要求发送新闻的时间间隔向用户发送一次新闻。
向Arugs注册的指令具有以下格式:Register Q_num Period
Q_num(0Q_num 3000)是用户的ID,Period()是间隔。注册后Period秒,结果会第一次到达。
所有的用户都有不同的Q_num。桐桐测试了一段时间后,想知道系统前K次给谁发送新闻了。如果同一时间发送多个新闻,以Q_num的升序排列。

输入格式

第一部分是注册指令,每条一行。指令数不超过10000,所有指令同时执行完。此部分以“#”结束。
第二部分仅一行一个整数,。

输出格式

输出前K个新闻发送到的用户的Q_num,每行一个。

样例

 输入样例

Register 2004 200
Register 2005 300
#
5

 输出样例

2004
2005
2004
2004
2005

分析

我们定义结构体储存三个元素:用户名[id],时间间隔[time0],下一次发生时间[time]
并且我们重载运算符,使得优先队列形成一个小根堆
我们将time初始值置为time0,并压入队列
我们模拟整个发新闻的过程
首先取出time最少的,输出其id,并且使得time+=time0
将这个元素压入队列

代码
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

const int M = 1e5 + 5;
struct user{
	int id;
	int time;
	int time0;
	bool operator < (const user x) const {
		if(time != x.time){
			return time > x.time;
		}
    	return id > x.id;
	}
};
priority_queue<user> q;
int l;

int main() {
	string x;
	for(; cin >> x && x != "#"; ) {
		user newest;
		cin >> newest.id >> newest.time0;
		newest.time = newest.time0;
		q.push(newest);
	}
	int t;
	scanf("%d", &t);
	for(; t > 0; t --) {
		user toop;
		toop = q.top();
		cout << toop.id << endl;
		toop.time += toop.time0;
		q.pop();
		q.push(toop);
	}
	return 0;
}

欲知后事如何,且听下回分解

你可能感兴趣的:(STL)