第一题 统计最少媒体包发送源个数
某媒体处理服务负责接收来自多个媒体发送源的媒休包,并根据收到的媒体包进行媒体渲染处理。当前有这样一个需求:给定收到的媒体包序列号列表,计算发送该媒体包的最少发送源个数。
约束:
网络上没有重传媒体包,即:同一个发送源发送的媒体包,序列号不会更复且字列号每次加1(不考虑回绕问题,65535是发送源发送的最后一个媒体包序列号);如果收到的媒体包序列号不满足该规则,说明这些媒体包必然来自于多个发送源。
解答要求
时间限制: C/C++100ms,其他语言:200ms
内存限制:C/C++32MB,其他语言:64MB
输入
第一行:seqs列表长度n1<=n<= 10^5
第二行:segs列表元素,元素之间通过空格隔开,任意媒体包序列号seqs[i],满足:0<=seqs[i]<=65535
输出
最少媒体包发送源个数
tips:测试用例在代码注释中
#include<iostream>
#include<vector>
using namespace std;
int main(){
int n;
cin >> n;
vector <int> seq(n); // 存放输入数据
for (int i=0; i<n; i++){
cin >> seq[i];
}
vector <int> count(65537, 0); // 若重复出现,必定是重复源
int max = 0, min = 65536;
for (int val: seq){ // 统计数据出现的次数,还有记录最大最小值
count[val+1]++;
if (val > max){
max = val;
}
if (val < min){
min = val;
}
}
vector <int>seqend(65537, 0); // 0~65536 共 65537个数字;存储以某序列号结束的序列数量
int result = 0;
int max_num = max + 1; // 因为count里面的元素也是加1的
int min_num = min + 1;
for (int i=min_num; i<=max_num; i++){ // 遍历最小数字到最大数字区间
while (count[i] > 0){ // 当存在记录时,把每一个记录消去,看能得到多少个result
if (seqend[i - 1] > 0){ // seqend有点波浪的感觉
seqend[i - 1]--;
seqend[i]++;
count[i]--;
}
else{
seqend[i]++;
count[i]--;
result++;
}
}
}
cout << result << endl;
return 0;
}
// 测试用例全部通过,提交通过率32% 》》 我想不出什么用例了,或者其他限制?
/*
官方测试用例:
18
1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10
5
65535 0 1 2 3
11
1 2 3 4 5 6 7 8 9 10 10
个人测试用例:
3
1 1 1
5
1 2 3 56123 56124
8
65534 65535 23 23 24 24 25 26
*/
第二题 铺设消防栓
消防员正在给城市铺设消防栓,城市的道路可以看作一个连通目无回路的图,每条道路有两个底座,消防栓必须铺设在底座上,每条道路必须有消防栓要盖;交叉路口只有一个消防栓底座;交叉路口的消防栓可以盖连接的所有道路,求至少需要多少个消防栓才能覆盖城市所有的道路?
解答要求
时问限制: C/C++1000ms,其他语言:2000ms
内存限制:C/C++256MB,其他语言: 512MB
输入
每个case,第一行一个整数n,表示底数,(1<=n<=1500)
接下来n行,每行以a:(b)这样的格式开头,a表示底座的编号(0<=a<=n-1),b表示与该底座相连接的底座数接下来b个数,表示与该底座相连的底座编号。
输出
一个数字,为需要的消防栓的最少个数
#include<iostream>
#include<vector>
#include<string>
#include<sstream>
#include<cstring>
using namespace std;
const int MAX = 1500;
vector <vector<int>> graph(MAX, vector <int>(0));
int dp[MAX][2];
bool visited[MAX];
void dfs(int u){
// u代表当前节点,v代表子节点
visited[u] = true; // 标记访问
dp[u][0] = 0; // 初始化,无消防栓,消防栓总数0
dp[u][1] = 1; // 初始化,该节点放置消防栓,消防栓总数1
for (int v:graph[u]){
if (!visited[v]){
dfs(v);
dp[u][0] += dp[v][1]; // 当前节点不放置消防栓,子节点必定放置有消防栓
dp[u][1] += min(dp[v][0], dp[v][1]); // 当前节点放置消防栓,子节点无所谓放置消防栓,取最小的
}
}
}
int main(){
int n;
cin >> n;
cin.get();
memset(visited, false, sizeof(visited));
for (int i=0; i<n; i++){
string line;
getline(cin, line);
// 处理输入
int pos = line.find(':');
int u = stoi(line.substr(0, pos));
int left_bracket = line.find('(', pos);
int right_bracket = line.find(')', left_bracket);
int num = stoi(line.substr(left_bracket + 1, right_bracket - left_bracket - 1));
// 构建图结构
istringstream iss(line.substr(right_bracket+1));
for (int j=0; j<num; j++){
int v;
iss >> v;
graph[u].push_back(v);
graph[v].push_back(u);
}
}
dfs(0); // 对图结构推导dp表
int result = min(dp[0][0], dp[0][1]); // 从节点0推导,取最小
cout << result <<endl;
return 0;
}
/*
官方测试用例:
3
0:(2) 1 2
1:(0)
2:(0)
8
0:(3) 1 2 3
1:(1) 6
2:(0)
3:(0)
6:(1) 7
7:(2) 4 5
4:(0)
5:(0)
*/
第三题 大礼包
某公司针对新用户推出大礼包,从任意一天注册开始,连续登陆天,每天可以领取一定的金币。领取金币的数量与该公司新设计的虚拟世界的日历相关,该日历一年有n个月,第i个月有di天,每一年都一样。在每个月第天会得到 1 个金币,第二天会得到 2 个金币,第三天会得到 3 个金币
后面依次类推。
请计算新用户注册后连续登陆天,最多可以获取多少金币。
请注意,连续登陆可能会跨年。
解笞要求
时间限制: C/C++500ms,其他语言:1000ms
内存限制:C/C++256MB,其他语言: 512MB
输入
第一行包含两个整数n和(1≤n≤2*10^5) ,分别表示一年中的月数和连续登陆的天数,第二行包含 n 个整数 d1, d2,…,dn,,di表示第i个月的天数(1 ≤di< 10^6)
用例保证,1≤r≤ d1+ d2+…+ dn。
输出
打印新用户连续登陆x天最多可以获取的金币数量
#include<iostream>
#include<vector>
using namespace std;
int main(){
int n,x;
cin >> n >> x;
vector <int> year;
for (int i=0; i<n; i++){
int day;
cin >> day;
for (int j=0; j<day; j++){
year.push_back(j+1);
}
}
int result = 0; // 保存结果
vector <int> dp(year.size(), 0);
// 统计前x天的总和,最基本的情况
int sum = 0;
for (int i=0; i<x; i++){
sum += year[i];
}
// 初始化
dp[x-1] = sum;
// 遍历超过x天的情况
for (int i=x; i<year.size(); i++){
dp[i] = max(dp[i-1], dp[i-1] - year[i-x] + year[i]); // 前一个总和 VS 去掉一个最初的值加上一个当前的值,相当于子序列和
if (dp[i] > result) result = dp[i];
}
cout << result;
return 0;
}
/*
官方测试用例:
3 2
1 3 1
3 6
3 3 3
5 6
4 2 3 1 3
*/
后记
考试时,第一题通过32%,第二题全部通过,第三题没写。现在给出的代码是考试后处理过的,并且写了第三题。
感觉华子的机试要有选择性的写,不能全部题都做(大佬除外),时间不够啊。选一题全部AC,最好是第二或第三题,然后再写一点另一题,能拿多少是多少。