BuaaCoding 026-050 Problems and Solutions
BuaaCoding 026-050 Problems and Solutions
- PART I 水题
- PART II 算法题
- 037 简单优先队列 (贪心 优先队列)
- 题目
- 分析
- 补充:c++优先队列的使用
- 解答
- 039 简单的二分法
- 题目
- 分析
- 解答
- 040 零崎的战争(最近点对)
- 041 大整数相乘
- 题目
- 分析
- 解答
- 042 不要不要丧心病狂(拐点维护的优雅写法)
- 题目
- 分析
- 解答
- 043 且听风吟之呆逼二三事(博弈论)
- 题目
- 分析
- 解答
- 046 李逍遥的仙剑客栈(贪心)
- 题目
- 分析
- 解答
- 050 零崎的补番计划Ⅰ (中位数法)
- 题目
- 分析
- 解答
- PART III 数学题
- 033 感受学长的爱意吧 (解方程组)
- 题目
- 分析
- 解答
- 035 活着的数 (数学规律真奇妙)
- 题目
- 分析
- 解答
PART I 水题
026 jhljx去太空 浮点数计算
027 Collatz Conjecture 奇偶归一猜想 模拟证明 + 记忆化加速
028 pluperfect digital invariant 水仙花数
029 A+Bi Problem 虚数相加
030 水水的的分数相加
031 神奇的桌子 线性检查
032 cool_breeze的袜子 配对计算
034 判断三角形
036 jhljx水水的签到题
037 水水的比较大小 浮点数比较大小
044 jhljx学函数
048 初见杀
049 盗墓笔记之怒海潜沙(最小公倍数)
045 大神杀 (浮点数回文判断)
这题随水却有注意点,题意,给出一个浮点数判断是否为回文数,12.21是,1.221不是。数据范围保证[0, 100000)小数位数不超过5位,精度1e-6。这个题已开始用字符串判断居然过不了,然后转而用double。其他注意点见代码中注释
#include <cstdio>
#define eps 1e-6
using namespace std;
//一般float准确的数位是6位 范围 -3.40E+38 ~ +3.40E+38
//double准确的数位是15位 范围 -1.79E+308 ~ +1.79E+308
bool judge_ph(double a) {a += eps; //这句话不可少 考虑到计算机存储误差1.5可能存成1.499999的情况 因为类型转化的时候直接截断for (int base = 1; base <= 10000; base *= 10) if (((long long) a / base) % 10 != (long long)(a * base * 10) % 10) return false;return true;
}
int main(int argc, char *argv[]) {double a;while(scanf("%lf", &a) != EOF) {if (judge_ph(a)) printf("Yes\n");else printf("No\n");}return 0;
}
047 不要不要数列求和 (离线 负数求余 ((a - b)%MOD + MOD) % MOD)
PART II 算法题
037 简单优先队列 (贪心 优先队列)
题目
最近,Nova君遇到了一件非常棘手的问题。他需要整理非常多的解题报告。每份解题报告的题目数量是不定的。Nova君每次需要将两份报告的题目解析合成到一份里。假设两份报告的题解数分别为a和b,那么合成这两份报告消耗Nova君a+b的hp值。现在有n份报告,题解数分别为a0,a1,a2,an-1,请问Nova最少消耗多少hp?
分析
最优二叉树,贪心算法
补充:c++优先队列的使用
//头文件
#inlude <queue>
//方法
empty()
pop() 删除第一个元素
push() 加入一个元素
size() 返回优先队列中拥有的元素个数
top() 返回优先队列中有最高优先级的元素
//优先级
priority_queue<int,vector<int>, greater<int> > q //最小优先队列
priority_queue<int> q //最大优先队列struct node { int x, y; friend bool operator < (node a, node b) { return a.x > b.x; //结构体中,x小的优先级高 }
};
解答
#include <cstdio>
#include <queue>
using namespace std;
int main(int argc, char *argv[]) {int n;while(scanf("%d", &n) != EOF) {priority_queue<int,vector<int>, greater<int> > q;for (int i = 0; i < n; i++) {int tmp;scanf("%d", &tmp);q.push(tmp);}int res = 0;while(q.size() > 1) {int merge = q.top();q.pop();merge += q.top();q.pop();res += merge;q.push(merge);}printf("%d\n", res);}
}
039 简单的二分法
题目
给你一非降序数列,以及一组查询,查询某一特定元素是否存在于数列之中,如果存在,则输出该元素首次出现的位置,否则输出"error"。
分析
二分查找,细节是相等时候的处理。
解答
#include <cstdio>
#define MAX 250005
using namespace std;
int a[MAX];
int bin_search(int a[], int l, int r, int tar) {while(l < r) {int m = (l + r) >> 1;if (a[m] < tar) {l = m + 1;} else if (a[m] > tar) {r = m - 1;} else {r = m;}}if (a[l] == tar) {return l;} else {return -1;}
}
int main(int argc, char *argv[]) {int n, m;while(scanf("%d%d", &n, &m) !=EOF) {for (int i = 0; i < n; i++) {scanf("%d", &a[i]);}for (int i = 0; i < m;i++) {int tar;scanf("%d", &tar);int idx = bin_search(a, 0, n - 1, tar);if (idx == -1) {printf("error\n");} else {printf("%d\n", idx + 1);}}}
}
040 零崎的战争(最近点对)
经典问题:详见我的另一篇博文
041 大整数相乘
题目
计算A*B
输入
第一个数为数据组数n
接下来n行,每行2个整数a,b
输出
对于每组数据,输出一行,a*b的值
分析
这题绝对是个坑,一开始无脑贴个大数模板,居然TLE,然后以为是必须要用分治策略,但是我又好奇为啥别人的代码比我的短。。
将信将疑之际,在牛客网找到了这个题,人家那个AC的代码连不仅是O(n2),还是一位一位算的,然而交上去居然过了。。。
但是牛客网这个答案不能处理负数,不能处理负数都过了,真的水。。。。
那为什么模板居然TLE啊啊啊啊啊啊
解答
#include <cstdio>
#include <string>
#include <iostream>
#include <cstring>
#define L 100005
using namespace std;string mult(string a, string b) {int signa = 1, signb = 1;if (a[0] == '-') {signa = -1;}if (a[0] == '+' || a[0] == '-') {a = a.substr(1);}if (b[0] == '-') {signb = -1;}if (b[0] == '+' || b[0] == '-') {b = b.substr(1);}int signres = signa * signb;int diga[L];int digb[L];int res[2*L + 5];memset(res, 0, sizeof(res));//反向存储for (int i = a.length() - 1; i >= 0; i--) {diga[a.length() - i - 1] = a[i] - '0';}for (int i = b.length() - 1; i >= 0; i--) {digb[b.length() - i - 1] = b[i] - '0';}for (int i = 0; i < a.length(); i++) {if (diga[i] == 0) {continue;}for (int j = 0; j < b.length(); j++) {res[i + j] += diga[i] * digb[j];}}for (int i = 0; i < a.length() + b.length(); i++) {res[i + 1] += res[i] / 10;res[i] %= 10;}int i = a.length() + b.length() - 1; while(i >= 0 && res[i] == 0) {i--;}string s = "";if (signres == -1) {s += '-';}while(i >= 0) {s += res[i] + '0';i--;}if (s == "-" || s == "") {s = "0";}return s;
}int main(){int n;scanf("%d", &n);getchar();string a, b;while(cin >> a >> b) {cout << mult(a, b) << endl;}
}
042 不要不要丧心病狂(拐点维护的优雅写法)
题目
jhljx又决定来出题了,上次上机以后有人说他是黑心学长,,噗。。。
肿么可以这样。。
松辰学妹对jhljx说不要不要丧心病狂。。jhljx说我给你出一道题,你要是答对了,你就赢了。。
松辰学妹说这还不简单啊。。
于是jhljx给了松辰学妹一个长度为n的数列A1,A2,A3……An。他说你能找出这个序列中a[i]-a[j]的最大值吗(保证i<j)?
松辰学妹说用数组啊。。jhljx说,没学数组,不准用。。用了你就跪了。。 松辰学妹说好吧。。这可怎么办呢?
输入
输入多组数据。
每组数据两行,第一行是一个正整数n(2<=n<=1000000)。第二行是n个数,每个数之间用空格隔开。保证这些数在int范围内。
输出
输出满足条件的最大值。
分析
很快发现其实是找最大下降子串,关键是怎么写得优雅。
我一开始写的代码一直在维护拐点的逻辑,十分丑陋,还老是WA。。。
优雅的写法是发现出现拐弯时修改一下左值即可。
另外关于res的初始值设定,我一般比较虚初始值,怕设小了,但是其实两个整数的差的最大值是INT_MIN-INT_MAX,所以其实res设成int还是可能爆的。。。
解答
#include <cstdio>
#define max(a, b) (a>b?a:b)
using namespace std;
int main(int argc, char *argv[]) {int n;while(scanf("%d", &n) != EOF) {int a, b, res = -10000000;scanf("%d", &a);for(int i = 1; i < n; i++) {scanf("%d", &b);res = max(res, a - b);if(a - b < 0) {a = b;}}printf("%d\n", res);}
}
043 且听风吟之呆逼二三事(博弈论)
题目
wzc是Tera里且听风吟公会的会长,本着为会员着想的心理,努力发展公会,公会人数也是日益壮大,慢慢的就加入了各大公会战,野外打狗的行列。
但是公会的某个妹子突然被呆比抢走并且已经发展到线下了(hhhh
广大会员和会长怎么能忍,随着呆比的发展,渐渐不见他上线,所以大家偷偷决定将他驱逐公会,但是会长wzc是个民主的会长(权限狗),他决定打开公会仓库,让呆比拿走一些金子作为他两个月来的贡献,但是wzc比较大方(抠门),定了下面的规矩:
wzc和呆比轮流取金子,wzc先取,第1次可以取任意多的金币,但不能全部取完.以后每次取的金子不能超过上次取的2倍,如果最后是wzc取完那么呆比取到的金子就要还回来,反之呆比可以拿走取到的金子。假设呆比和wzc都竭尽全力想要赢。
wzc沉迷于公会战和各种事物不能自拔所以需要你来判断呆比能不能全身而退。
输入
输入有多组
.每组1行只有一个数n,代表仓库里的金子数,wzc很穷(有钱)所以2<=n<2^31。
输出
如果wzc取完 则输出"Oh,yes!" 如果呆比取完 则输出"Oh,holly shit!"(我英语学的不好请原谅)
分析
本质是一个fibonacci博弈
博弈论的系统梳理,详见我的另一篇博文
解答
#include <iostream>
#define END 46
using namespace std;
int fib[END];
//fib第46个值 开始溢出
int main(int argc, char *argv[]) {fib[0] = 1;fib[1] = 1;for (int i = 2; i < END; i++) {fib[i] = fib[i - 1] + fib[i-2];}int n;while(scanf("%d", &n) != EOF) {int i;for (i = 0; i < END; i++) {if (fib[i] == n) {break;}}if (i == END) {printf("Oh,yes!\n");} else {printf("Oh,holly shit!\n");}}return 0;
}
046 李逍遥的仙剑客栈(贪心)
题目
给你一个数n表示有多少个桌子,接下来给你一段整数序列表示每个桌上需要的酒量(假设这些桌子在一条直线上,且每个桌子之间的距离都是1),正数表示多放了 几瓶酒,负数表示应该放多少瓶酒。请你帮Arthur算一下他提着酒走的最短路程是多少。对了,Arthur体力太渣,一次只能拿一瓶酒。
输入
第一行一个数T表示有T组数据。
接下来T组数据,每组数据有2行。
第一行一个数n(1<=n<=1000),表示桌子数量,
接下来第二行有一段数列Ai(|Ai|<=1000),表示每个桌子上应该放的酒。保证数列总和为0
输出
对于每组测试数据,输出一个数,表示Arthur拿着酒走的最少总路程。
分析
贪心的问题从来都是这样,想起来难,写起来容易。。
第一个观察,n和数字的大小都是1000以内,这就说明,不能简单地说n是1000就去尝试一个O(n2)的解法,这里显然是两个数字范围相乘不会爆,只是说用整型不会溢出。
对于一个正数位置,把它往最近的负数上方不亏,一样近的情况是无所谓的,因为酒瓶之间无差异,人不带酒走路无代价。所以一样近的两个位置选取不会影响后面的选择。正向和反向也是没有差异的,所以带着负数走路相当于反相携带酒瓶。
这看起来像一道经典题,还是记住吧。贪心问题想通过证明推出来需要的数学功底绝非一日之功。。。。
解答
#include <cstdio>
using namespace std;
int main(int argc, char *argv[]) {int T;scanf("%d", &T);while(T--) {int n;scanf("%d", &n);int res = 0;int count = 0;while(n--) {int t;scanf("%d", &t);res += (count > 0? count: -count);count += t;}printf("%d\n", res);}
}
050 零崎的补番计划Ⅰ (中位数法)
题目
给定n个不一样的数,求第k大的数。
分析
排序O(n logn)
但是可以有两个更快的算法时间复杂度为O(n)
解答
排序秒过 代码也很短 但是我们追求卓越。。。
详见我的另一篇博文。
PART III 数学题
033 感受学长的爱意吧 (解方程组)
题目
奇怪的人类觉得最近在3楼吃香锅的时候,等待的人生真是寂寞如雪。
于是他拿了1副半的筷子开始摆弄,还脑洞大开地以桌面中心为原点建了个xOy的坐标轴=、= 然后,他开始算交点的坐标了……
分析
两两联立解方程组,注意平行情况的特殊判断。采用方程表示法可以不用讨论斜率不存在的情况,简单了不少,随后去重和排序暴力法即可,因为最多三个解。
小细节:可能出现-0.00的情况,这个加个特判吧。
解方程组写得还行,但是后面去重和排序写得比较丑。
解答
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
using namespace std;
double * cal_two(int a1, int b1, int c1, int a2, int b2, int c2) {double * res = NULL;if ((a1 == 0 && b1 == 0) || (a2 == 0 && b2 == 0)) {//有直线不存在return res;} else if (a1 * b2 == a2 * b1) {//直线平行return res;} else {//一般情况res = (double*)malloc(sizeof(double)*2);res[0] = (double)(b1*c2 - b2*c1) / (a1*b2 - a2*b1);res[1] = (double)(a2*c1 - a1*c2) / (a1*b2 - a2*b1);}return res;
}
int main(int argc, char *argv[]) {int a[9];while(scanf("%d%d%d%d%d%d%d%d%d", &a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6], &a[7], &a[8])!=EOF) {// 求解double ** reses = (double**)malloc(sizeof(double*)*3);reses[0] = cal_two(a[0], a[1], a[2], a[3], a[4], a[5]);reses[1] = cal_two(a[0], a[1], a[2], a[6], a[7], a[8]);reses[2] = cal_two(a[3], a[4], a[5], a[6], a[7], a[8]);int no_dup[3] = {-1, -1, -1};int cnt = 0;// 去重for (int i = 0; i < 3; i++) {if (reses[i] != NULL) {int j;for (j = 0; j < cnt; j++) {if (!(reses[no_dup[j]][0] == reses[i][0] && reses[no_dup[j]][1] == reses[i][1])) {continue;} else {break;}}if (j == cnt) {no_dup[cnt++] = i;}}}// 排序for (int i = 0; i < cnt; i++) {for (int j = i+1; j < cnt; j++) {if (reses[no_dup[i]][0] - reses[no_dup[j]][0] > 0.00001) {int tmp = no_dup[i];no_dup[i] = no_dup[j];no_dup[j] = tmp;} else if (fabs(reses[no_dup[i]][0] - reses[no_dup[j]][0]) < 0.00001) {if (reses[no_dup[i]][1] - reses[no_dup[j]][1] > 0.00001) {int tmp = no_dup[i];no_dup[i] = no_dup[j];no_dup[j] = tmp;}}}}// 输出printf("%d\n", cnt);for (int i = 0; i < cnt; i++) {double a = fabs(reses[no_dup[i]][0]) < 0.001? 0.0: reses[no_dup[i]][0];double b = fabs(reses[no_dup[i]][1]) < 0.001? 0.0: reses[no_dup[i]][1];printf("%.2f %.2f\n", a, b);}}return 0;
}
035 活着的数 (数学规律真奇妙)
题目
已知1和3是一个“活着的数”。
并且如果a和b是一个“活着的数”。
那么2+ab+2a+2b也是一个“活着的数”。
例如1和1是“活着的数”。
那么2+1+2+2=7也是一个活着的数。
分析
第一反应是递推,然后离线查找,但是n的范围是INT_MAX,所以显然不行。
这题要从数学等式上下功夫。
2 + ab +2a + 2b = c
4 +ab + 2a + 2b = c + 2
(a + 2)(b + 2) = c + 2
也就是说,任意“活着的数”+2 都是之前“活着的数”+2的乘积。所以对任何“活着的数”n,有n+2 = (1 + 2)p(3 + 2)q。
解答
#include <iostream>
using namespace std;int main(int argc, char *argv[]) {int n;while(scanf("%d", &n) != EOF) {n += 2;while (n % 5 ==0) {n /= 5;}while (n % 3 == 0) {n /= 3;}if (n == 1) {printf("Yes\n");} else {printf("No\n");}} return 0;
}
BuaaCoding 026-050 Problems and Solutions相关推荐
- BuaaCoding 001-025 Problems and Solutions
BuaaCoding 001-025 Problems and Solutions PART I 水题(都是语言题) PART II 简单基础算法题 009 零崎的人间冒险Ⅰ (汉诺塔递归) 题目 分 ...
- AMC Problems and Solutions
AMC Problems and Solutions:https://artofproblemsolving.com/wiki/index.php/AMC_Problems_and_Solutions ...
- Problems and Solutions
1.Python相关 1.1 pip安装报错:is not a supported wheel on this platform 安装包是[pywin32-305-cp36-cp36m-win_amd ...
- 剑指 Offer(专项突击版)Java 持续更新....
剑指 Offer(专项突击版) 刷题链接: https://leetcode-cn.com/problem-list/e8X3pBZi/?page=1 No.001 题目: 整数除法 1. 刷题链接: ...
- 【转】Beagleboard:BeagleBoneBlack
原文网址:http://elinux.org/Beagleboard:BeagleBoneBlack Did you know that elinux.org has Mailing Lists? P ...
- 【C++】C++好书推荐
一.吴咏炜推荐 1.入门级 Bjarne Stroustrup, A Tour of C++, 2nd ed. Addison-Wesley, 2018 中文版: 王刚译,<C++ 语言导学&g ...
- 网络安全从事工作分类_那么,您想从事安全工作吗?
网络安全从事工作分类 by Parisa Tabriz 由Parisa Tabriz 那么,您想从事安全工作吗? (So, you want to work in security?) Every o ...
- 计算机财务管理相关文献,财务管理外文参考文献(精选文献105个)
任何事物总是与一定的环境相联系.存在和发展的 ,财务管理也不例外.不同时期.不同国家.不同领域的财务管理之所以有不同的特征 ,都是因为影响财务管理的环境因素不尽相同.企业在许多方面同生物体一样 ,如果 ...
- 推荐一些C++经典书籍
c++程序设计教程 c++编程思想 c++大学教程 c++程序设计语言 数据结构算法与应用c++语言描述 c++标准模板库------自修教程与参考手册 泛型编程与STL 深度探索c++ ...
最新文章
- 文章如何做伪原创 SEO大神教你几招做原创网站文章的心得
- C#后台线程和UI的交互
- 【Kaggle-MNIST之路】CNN结构再改进+交叉熵损失函数(六)
- 删除bin后,Eclipse重新编译项目
- 微软发布 Power BI 2020 上半年发行计划
- php操作剪贴板内容代码,JavaScript操作剪贴板的实现方法介绍
- onnx格式转tensorRT
- POJ1060 HDU1343 ZOJ1026 UVALive2323 Modular multiplication of polynomials题解
- Java高并发之设计模式,设计思想!
- 数据库实现中文汉字排序终极指南
- HDU 4289 Control (最大流最小割)
- 冰点还原精灵、影子系统区别哪个好
- ACM篇:Uva -- 253 Cude Painting
- 谁说文艺青年开花店必亏,我用3年时间挣了20万
- 复合辛普森公式matlab,复合梯形公式、复合辛普森公式 matlab
- WinKawaks详尽使用说明
- 黑科技智能家电新生儿“智能冰箱”
- matlab中screen函数,13 PTB Screen 函数
- 人工蜂群算法python_人工蜂群算法简介与程序分析
- Python 趋势:当今最热门语言的热门话题
热门文章
- 外媒看华为鸿蒙系统,华为鸿蒙系统大有可期!获外媒力挺:鸿蒙OS系统装机量将破4亿...
- [docker] docker删除<none>/dangling/悬空镜像
- MSIL简介 - Part 3 - 定义类型
- google 隐私权政策_如何阻止不断出现的Google隐私权提醒消息?
- 玩转ECharts制作图表之散点图
- 电子书下载:iPhone and iPad Apps for Absolute Beginners iOS 5 Edition
- java的相对路径用法_java项目中的绝对路径和相对路径用法说明
- 为什么我们活得比较累?
- emlogPro实现模板预览功能(包含模板设置数据)
- app语聊房间测试要点