[Offer收割]编程练习赛4及参考

2024-05-25 01:18

本文主要是介绍[Offer收割]编程练习赛4及参考,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转载BLXG博客

A.满减优惠

问题
时间限制:10000ms 单点时限:1000ms 内存限制:256MB

描述
最近天气炎热,小Ho天天宅在家里叫外卖。他常吃的一家餐馆一共有N道菜品,价格分别是A1, A2, … AN元。并且如果消费总计满X元,还能享受优惠。小Ho是一个不薅羊毛不舒服斯基的人,他希望选择若干道不同的菜品,使得总价在不低于X元的同时尽量低。

你能算出这一餐小Ho最少消费多少元吗?

输入
第一行包含两个整数N和X,(1 <= N <= 20, 1 <= X <= 100)

第二行包含N个整数A1, A2, …, AN。(1 <= Ai <= 100)

输出
输出最少的消费。如果小Ho把N道菜都买了还不能达到X元的优惠标准,输出-1。

样例输入
10 50
9 9 9 9 9 9 9 9 9 8
样例输出
53
分析
题目简单理解起来就是,从数组中选出若干个数,使得这些数的和大于X,并且尽可能的小。

根据数据范围的限制,数组中最多只有20个数,所有这些和的数量为1^20个。数据量并不大。

暴力应该可以搞定:枚举数的所有数的组合情况,使用int32_t表示每个数的选择情况,int32_t的第i位表示数组中下标为i的数是否选中。

AC程序
下面是C++实现的完整代码:

#include <iostream>
#include <vector>using namespace std;int main(void)
{int n, x, sum = 0;cin >> n >> x;vector<int> nums(n);for (int i = 0; i < n; ++i) {cin >> nums[i];sum += nums[i];}if (sum < x) {cout << -1 << endl;return 0;}int ret = sum;for (int i = 1, iend = 1 << n; i < iend; ++i) {if (ret == x)break;int cur = 0;for (int j = 0; j < n; ++j) {if (((1 << j) & i)) // select jth number from numscur += nums[j];if (cur >= x) { // because there is no negative number in numsbreak;}}// update minimum value greater than xif (cur >= x && cur < ret)ret = cur;}cout << ret << endl;return 0;
}

B. 积水的城市

问题
时间限制:11000ms 单点时限:1000ms 内存限制:256MB

描述
如下图所示,某市市区由M条南北向的大街和N条东西向的道路组成。其中由北向南第i条路和第i+1条路之间的距离是Bi (1 <= i &lht; N),由西向东第i条街和第i+1条街之间的距离是Ai (1 <= i < M)。

drown

小Ho现在位于第x条路和第y条街的交叉口,他的目的地是第p条路和第q条街的交叉口。由于连日降雨,城市中有K个交叉口积水太深不能通行。小Ho想知道到达目的地的最短路径的长度是多少。

输入
第一行包含两个整数N和M。(1 <= N, M <= 500)

第二行包含N-1个整数, B1, B2, B3, … BN-1。(1 <= Bi <= 100)

第三行包含M-1个整数, A1, A2, A3, … AM-1。(1 <= Ai <= 100)

第四行包含一个整数K,表示积水的交叉口的数目。 (0 <= K <= 30)

以下K行每行包含2个整数,X和Y,表示第X条路和第Y条街的交叉口积水。(1 <= X <= N, 1 <= Y <= M)

第K+5行包含一个整数Q,表示询问的数目。 (1 <= Q <= 10)

以下Q行每行包含4个整数x, y, p, q,表示小Ho的起止点。起止点保证不在积水的交叉口处。 (1 <= x, p <= N, 1 <= y, q <= M)

输出
对于每组询问,输出最短路的长度。如果小Ho不能到达目的地,输出-1。

样例输入

4 5
2 4 1
3 3 3 2
3
1 3
2 3
3 2
1
1 2 2 4
样例输出

24
分析
有障碍的最短路径问题,对于无权的格子问题,只需要利用BFS探索即可。本题中“路”和“街”的长度可能不同,因此,利用SPFA算法。 也就是在BFS的基础上,记录源点到其它每个点的距离,当新探索出的路径长度更小时,更新记录,并将当前状态入栈。 当遇到“积水”的路口时,直接丢弃该状态即可表示不能通过本路口。

AC程序

#include <iostream>
#include <cstring>
#include <set>
#include <queue>
#include <utility>#define N 501
#define M 501
#define UDF 0x3f3f3f3fusing namespace std;int A[M];
int B[N];
int n, m;
set<pair<int, int>> dead;struct Status{int x, y, d;Status(int a, int b, int c) : x(a), y(b), d(c) {}
};int visit[N][M];int solve(int x, int y, int p, int q)
{static int dx[] = {-1, 0, 1, 0};static int dy[] = {0, 1, 0, -1};queue<Status> sq;sq.push(Status(x, y, 0));visit[x][y] = 0;while (!sq.empty()) {int cx = sq.front().x;int cy = sq.front().y;int cd = sq.front().d;sq.pop();// explore 4 directionsfor (int i = 0; i < 4; ++i) {int nx = cx + dx[i];int ny = cy + dy[i];// skip invalid coordinates and water crossingif (nx <= 0 || ny <= 0 || nx > n || ny > m || dead.find(make_pair(nx, ny)) != dead.end())continue;int nd = dx[i] == 0 ? cd + A[min(cy, ny)] : cd + B[min(cx, nx)];// skip longer pathif (visit[nx][ny] <= nd)continue;// skip the destination itselfif (nx != p || ny != q)sq.push(Status(nx, ny, nd));visit[nx][ny] = nd;}}return visit[p][q] == UDF ? -1 : visit[p][q];
}int main(void)
{cin >> n >> m;for (int i = 1; i < n; ++i)cin >> B[i];for (int i = 1; i < m; ++i)cin >> A[i];int k;cin >> k;for (int i = 0; i < k; ++i) {int x, y;cin >> x >> y;dead.insert(make_pair(x, y));}int t;cin >> t;for (int i = 0; i < t; ++i) {int x, y, p, q;cin >> x >> y >> p >> q;memset(visit, UDF, sizeof(visit));cout << solve(x, y, p, q) << endl;}return 0;
}

C. 罚抄一百遍

问题
时间限制:10000ms 单点时限:1000ms 内存限制:256MB

描述
小Ho忘了做英语作业,被老师罚抄某段文本N遍。抄写用的作业纸每行包含M个格子,每个格子恰好能填写一个字符或者空格。抄写过程中单词不能跨行,如果某行剩余的格子不足以写完一个单词,那么这个单词需要写在下一行。单词间的空格不能省略。

例如在M=9的作业纸上写2遍”Good good study day day up”:

123456789
Good good
study
day day
up Good
good
study day
day up
小Ho想知道当他抄写完N遍以后,最后一个字符在第几行、第几列。

输入
第一行包含两个整数N和M。

第二行包含要抄写的文本。文本只包含大小字母和空格,并且单词之间只有一个空格。

对于40%的数据,1 <= N, M <= 1000

对于100%的数据,1 <= N, M <= 1000000000, M >= 文本中最长的单词的长度,文本长度不超过100个字符。

输出
最后一个字符的行号和列号。

样例输入

2 9
Good good study day day up
样例输出

7 7
分析
根据题意的描述,可知当抄写的次数足够多时,必须存在循环节,也就是当抄写次数足够多时,必然存在i, j,使得第i次抄写和第j次抄写开始的列数相同。寻找循环节的方法也很简单,只需要用Hash表记录,每次抄写时开始的行数x,列数y即可。

由于题目要求每两个单词之间必须存在一个空格,第二遍抄写的第一个单词与第一遍的最后一个单词之间,也要存在一个空格。 所以我们可以把要抄写的字符串前加上一个空格,以方便处理。那么此时,第一遍抄写时开始的行x=1,列y=-1。

当我们利用Hash表找到循环节后,即可以跳过中间重复的模拟过程。

此外,要小心行数x溢出int32_t表示范围。

AC程序

#include <iostream>
#include <unordered_map>
#include <vector>using namespace std;// copy n times starting at (x, y)
void ncopy(const vector<int> &nums, int n, int m, long long &x, int &y)
{for (int i = 0; i < n; ++i) {for (auto num : nums) {if (y == m)y = 0, ++x;++y;if (y + num > m)y = 0, ++x;y += num;}}
}int main(void)
{int n, m;cin >> n >> m;vector<int> nums;string s;while(cin >> s)nums.push_back(s.size());// record nth copy starting at (x, y) => dict[y] = make_pair(n, x)unordered_map<int, pair<int, long long>> dict;long long x = 1;int y = -1;for (int i = 1; i <= n; ++i) {ncopy(nums, 1, m, x, y);if (dict.find(y) != dict.end()) { // find the repetend// fast forward to skip the repetendlong long remain = (n - i) % (i - dict[y].first); // add x by repetend's rowsx += (n - i) / (i - dict[y].first) * (x - dict[y].second);// copy the reset timesncopy(nums, remain, m, x, y);break;}// record ith copy starting at (x, y)dict.emplace(y, make_pair(i, x));}cout << x << ' ' << y << endl;return 0;
}

D. 分隔相同整数

问题
时间限制:10000ms 单点时限:1000ms 内存限制:256MB

描述
给定一个包含N个整数的数组A。你的任务是将A重新排列,使得任意两个相等的整数在数组中都不相邻。

如果存在多个重排后的数组满足条件,输出字典序最小的数组。

这里字典序最小指:首先尽量使第一个整数最小,其次使第二个整数最小,以此类推。

输入
第一行包含一个整数N,表示数组的长度。(1 <= N <= 100000)

第二行包含N个整数,依次是 A1, A2, … AN。(1 <= Ai <= 1000000000)

输出
输出字典序最小的重排数组。如果这样的数组不存在,输出-1。

样例输入

4
2 1 3 3
样例输出

1 3 2 3
分析
将一个由长度为n(n>1)同一字母组成的字符串分隔开,显然需要n-1个其它字符。 由此,我们可以统计,输入字符串的每个数字出现的次数Bi,我们可以按照如下规则排列数字:

若出现最多的数字x的次数为Bx,则分隔x至少需要Bx-1个数字,若Bx + Bx - 1 < N,说明还有充足的字符可以分隔x,故输出与前次输出不同的最小数字即可;
否则,说明此时必须输出x,因为,分隔x的字符即将不足。此时,若x与前次输出数字相同,则无解。
因此,我们可以利用Hash表,统计各数字出现的次数,将利用二叉查找树,得到次数最多的数字。 此处,不使用大根堆的原因是,当输出的数字不是次数最多的数字,即输出的数字不是大根堆的堆顶元素, 此时,更新相应元素的次数后,需要调整堆,以满足大根堆的性质,这个操作比较麻烦。

AC程序

#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <cassert>using namespace std;bool solve(vector<int> &s)
{map<int, int> dict;// count every number's timesfor (auto c : s)++dict[c];set<pair<int, int>> heap;// use black-red tree simulate heapfor (auto d : dict)heap.insert(make_pair(d.second, d.first));vector<int>::size_type size = s.size(), idx = 0;int last = -1;while (size) {auto iter = dict.find(heap.rbegin()->second);if (size/2 < iter->second) { // rule 2if (last == iter->first) // fail to rearrangereturn false;} else { // rule 1iter = dict.begin();if (iter->first == last)++iter;assert(iter != dict.end());}// output a numbers[idx++] = iter->first;// update heapheap.erase(make_pair(iter->second, iter->first));iter->second -= 1;if (iter->second == 0)dict.erase(iter);elseheap.insert(make_pair(iter->second, iter->first));last = s[idx-1];--size;}return true;
}int main(void)
{int n;cin >> n;vector<int> nums(n);for (int i = 0; i < n; ++i)cin >> nums[i];if (!solve(nums))cout << -1 << endl;else {cout << nums[0];for (int i = 1; i < n; ++i)cout << ' ' << nums[i];cout << endl;}return 0;
}

第三题较难。

这篇关于[Offer收割]编程练习赛4及参考的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1000074

相关文章

Java并发编程之如何优雅关闭钩子Shutdown Hook

《Java并发编程之如何优雅关闭钩子ShutdownHook》这篇文章主要为大家详细介绍了Java如何实现优雅关闭钩子ShutdownHook,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起... 目录关闭钩子简介关闭钩子应用场景数据库连接实战演示使用关闭钩子的注意事项开源框架中的关闭钩子机制1.

shell编程之函数与数组的使用详解

《shell编程之函数与数组的使用详解》:本文主要介绍shell编程之函数与数组的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录shell函数函数的用法俩个数求和系统资源监控并报警函数函数变量的作用范围函数的参数递归函数shell数组获取数组的长度读取某下的

揭秘Python Socket网络编程的7种硬核用法

《揭秘PythonSocket网络编程的7种硬核用法》Socket不仅能做聊天室,还能干一大堆硬核操作,这篇文章就带大家看看Python网络编程的7种超实用玩法,感兴趣的小伙伴可以跟随小编一起... 目录1.端口扫描器:探测开放端口2.简易 HTTP 服务器:10 秒搭个网页3.局域网游戏:多人联机对战4.

Java并发编程必备之Synchronized关键字深入解析

《Java并发编程必备之Synchronized关键字深入解析》本文我们深入探索了Java中的Synchronized关键字,包括其互斥性和可重入性的特性,文章详细介绍了Synchronized的三种... 目录一、前言二、Synchronized关键字2.1 Synchronized的特性1. 互斥2.

Python异步编程中asyncio.gather的并发控制详解

《Python异步编程中asyncio.gather的并发控制详解》在Python异步编程生态中,asyncio.gather是并发任务调度的核心工具,本文将通过实际场景和代码示例,展示如何结合信号量... 目录一、asyncio.gather的原始行为解析二、信号量控制法:给并发装上"节流阀"三、进阶控制

C#多线程编程中导致死锁的常见陷阱和避免方法

《C#多线程编程中导致死锁的常见陷阱和避免方法》在C#多线程编程中,死锁(Deadlock)是一种常见的、令人头疼的错误,死锁通常发生在多个线程试图获取多个资源的锁时,导致相互等待对方释放资源,最终形... 目录引言1. 什么是死锁?死锁的典型条件:2. 导致死锁的常见原因2.1 锁的顺序问题错误示例:不同

PyCharm接入DeepSeek实现AI编程的操作流程

《PyCharm接入DeepSeek实现AI编程的操作流程》DeepSeek是一家专注于人工智能技术研发的公司,致力于开发高性能、低成本的AI模型,接下来,我们把DeepSeek接入到PyCharm中... 目录引言效果演示创建API key在PyCharm中下载Continue插件配置Continue引言

C#反射编程之GetConstructor()方法解读

《C#反射编程之GetConstructor()方法解读》C#中Type类的GetConstructor()方法用于获取指定类型的构造函数,该方法有多个重载版本,可以根据不同的参数获取不同特性的构造函... 目录C# GetConstructor()方法有4个重载以GetConstructor(Type[]

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal