试题A:握手问题
#include <iostream>
using namespace std;
int main()
{
int count = 0;
for (int i = 0; i < 50; i++)
for (int j = i + 1; j < 50; j++)
count++;
for (int i = 0; i < 7; i++)
for (int j = i + 1; j < 7; j++)
count--;
cout << count;
return 0;
}
先将50个人之间握手的次数求出,再减去7个人之间相互握手的次数即可
试题B:小球反弹
#include <iostream>
#include <cmath>
using namespace std;
typedef long long ll;
int gcd(int a,int b)
{
return b==0?a:gcd(b,a%b);
}
int main() {
int y = 233333;
int x = 343720;
int p=15*y;
int q=17*x;
int g=gcd(p,q);
p/=g;
q/=g;
int t=2*p*x/15;
double ans=t*sqrt(15*15+17*17)*1.0;
printf("%.2lf",ans);
return 0;
}
设小球在x的方向上走了p个来回,在y方向上走了q个来回,经过了时间t后回到了起点
则t*dx=2px,t*dy=2qy,化简可得p/q=dx*y/dy*x,t=2*p*x/dx
试题C:好数
题目描述
一个整数如果按从低位到高位的顺序,奇数位(个位、百位、万位 · · · )上的数字是奇数,偶数位(十位、千位、十万位 · · · )上的数字是偶数,我们就称之为“好数”。给定一个正整数 N,请计算从 1 到 N 一共有多少个好数。
输入格式
一个整数 N。
输出格式
一个整数代表答案。
样例输入
24
样例输出
7
提示
对于第一个样例,24 以内的好数有 1、3、5、7、9、21、23,一共 7 个。试题 C: 好数 4第十五届蓝桥杯大赛软件赛省赛 C/C++ 大学 B 组【评测用例规模与约定】对于 10% 的评测用例,1 ≤ N ≤ 100。对于 100% 的评测用例,1 ≤ N ≤ 107。
#include <iostream>
using namespace std;
int main()
{
int count = 0, n;
cin >> n;
for (int i = 1; i <= n; i++)
{
int x = i,flag = 1;
while (x)
{
int y = x % 10;
x /= 10;
if (flag == 1)
{
if (y % 2 == 0)
{
flag = 0;
break;
}
}
else
{
if (y % 2 != 0)
{
flag = 0;
break;
}
}
flag *= -1;
}
if (flag != 0) count++;
}
cout << count;
return 0;
}
试题D:R格式
题目描述
小蓝最近在研究一种浮点数的表示方法:R 格式。对于一个大于 0 的浮点数 d,可以用 R 格式的整数来表示。给定一个转换参数 n,将浮点数转换为 R格式整数的做法是:
1. 将浮点数乘以 2^n;
2. 四舍五入到最接近的整数。
输入格式
一行输入一个整数 n 和一个浮点数 d,分别表示转换参数,和待转换的浮点数。
输出格式
输出一行表示答案:d 用 R 格式表示出来的值。
样例输入
2 3.14
样例输出
13
提示
【样例说明】
3.14 × 22 = 12.56,四舍五入后为 13。
【评测用例规模与约定】
对于 50% 的评测用例:1 ≤ n ≤ 10,1 ≤ 将 d 视为字符串时的长度 ≤ 15。
对于 100% 的评测用例:1 ≤ n ≤ 1000,1 ≤ 将 d 视为字符串时的长度≤ 1024;保证 d 是小数,即包含小数点。
#include <iostream>
#include<vector>
using namespace std;
int main()
{
int n;
cin >> n;
string s;
cin >> s;
for (int i = 0; i < n; i++)
{
int sum = 0;
for (int j = s.size() - 1; j >= 0; j--)
{
if (s[j] == '.') continue;
int sum2 = (s[j] - '0') * 2;
s[j] = ((sum2 + sum) % 10) + '0';
sum = sum2 / 10;
if (j == 0 && sum != 0)
{
s.insert(s.begin(), sum + '0');
}
}
}
for (int i = 0; i < s.size(); i++)
{
if (s[i] == '.')
{
if (i + 1 < s.size() && s[i + 1] - '0' >= 5)
{
int sum = 1;
for (int j = i - 1; j >= 0; j--)
{
int x = s[j] - '0';
x += sum;
s[j] = x % 10 + '0';
sum = x / 10;
if (sum == 0) break;
}
if (sum > 0) s.insert(s.begin(), sum + '0');
}
break;
}
}
for (int i = 0; i < s.size(); i++)
{
if (s[i] == '.') break;
cout << s[i];
}
return 0;
}
这道题使用的是高精度乘法,第一个for循环是乘法,第二个for循环是对数据进行四舍五入
试题F:数字接龙
小蓝最近迷上了一款名为《数字接龙》的迷宫游戏,游戏在一个大小为N × N 的格子棋盘上展开,其中每一个格子处都有着一个 0 . . . K − 1 之间的整数。游戏规则如下:
1. 从左上角 (0, 0) 处出发,目标是到达右下角 (N − 1, N − 1) 处的格子,每一步可以选择沿着水平/垂直/对角线方向移动到下一个格子。
2. 对于路径经过的棋盘格子,按照经过的格子顺序,上面的数字组成的序列要满足:0, 1, 2, . . . , K − 1, 0, 1, 2, . . . , K − 1, 0, 1, 2 . . . 。
3. 途中需要对棋盘上的每个格子恰好都经过一次(仅一次)。
4. 路径中不可以出现交叉的线路。例如之前有从 (0, 0) 移动到 (1, 1),那么再从 (1, 0) 移动到 (0, 1) 线路就会交叉。
为了方便表示,我们对可以行进的所有八个方向进行了数字编号,如下图2 所示;因此行进路径可以用一个包含 0 . . . 7 之间的数字字符串表示,如下图 1是一个迷宫示例,它所对应的答案就是:41255214。
现在请你帮小蓝规划出一条行进路径并将其输出。如果有多条路径,输出字典序最小的那一个;如果不存在任何一条路径,则输出 −1。
输入格式
第一行包含两个整数 N、K。接下来输入 N 行,每行 N 个整数表示棋盘格子上的数字。
输出格式
输出一行表示答案。如果存在答案输出路径,否则输出 −1。
样例输入
3 3 0 2 0 1 1 1 2 0 2
样例输出
41255214
提示
【样例说明】行进路径如图 1 所示。
【评测用例规模与约定】对于 80% 的评测用例:1 ≤ N ≤ 5。对于 100% 的评测用例:1 ≤ N ≤ 10,1 ≤ K ≤ 10。
#include <iostream>
#include<vector>
using namespace std;
int dirss[8][2] = { {-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1} };
bool hash1[11][11][11][11];
bool hash2[11][11];
vector<int> sum;
void dfs(int x, int y, vector<vector<int>>& v, vector<int>& count, int k ,int n)
{
if (sum.size() > 0) return;
if (x == v.size() - 1 && y == v.size() - 1)
{
if (count.size() == (n*n) - 1)
{
sum = count;
}
return;
}
if (count.size() == (n * n) - 1) return;
for (int i = 0; i < 8; i++)
{
int nx = x + dirss[i][0], ny = y + dirss[i][1];
if (nx >= 0 && nx < v.size() && ny >= 0 && ny < v.size() && !hash2[nx][ny]&& !hash1[nx][y][x][ny])
{
if (v[nx][ny] == v[x][y] + 1 || (v[nx][ny] == 0 && v[x][y] == k - 1))
{
hash2[nx][ny] = true;
hash1[x][y][nx][ny] = true;
hash1[nx][ny][x][y] = true;
count.push_back(i);
dfs(nx, ny, v, count, k,n);
hash2[nx][ny] = false;
hash1[x][y][nx][ny] = false;
hash1[nx][ny][x][y] = false;
count.pop_back();
}
}
}
}
int main()
{
int n, k;
cin >> n >> k;
vector<vector<int>> v(n, vector<int>(n));
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
cin >> v[i][j];
vector<int> count;
hash1[0][0][0][0] = true;
hash2[0][0] = true;
dfs(0, 0, v, count, k, n);
if (sum.size() == 0) cout << -1;
for (int i = 0; i < sum.size(); i++)
{
cout << sum[i];
}
return 0;
}
这道题用的是dfs,如何判断是否交叉,只需要关注斜线是否交叉即可,横竖线不可能存在交叉,斜线交叉的坐标画图即可理解
试题G:爬山
小明这天在参加公司团建,团建项目是爬山。在 x 轴上从左到右一共有 n座山,第 i 座山的高度为 hi。他们需要从左到右依次爬过所有的山,需要花费的体力值为 S = Σni=1hi。
然而小明偷偷学了魔法,可以降低一些山的高度。他掌握两种魔法,第一种魔法可以将高度为 H 的山的高度变为 ⌊√H⌋,可以使用 P 次;第二种魔法可以将高度为 H 的山的高度变为 ⌊H/2⌋,可以使用 Q 次。并且对于每座山可以按任意顺序多次释放这两种魔法。
小明想合理规划在哪些山使用魔法,使得爬山花费的体力值最少。请问最优情况下需要花费的体力值是多少?
输入格式
输入共两行。
第一行为三个整数 n,P,Q。
第二行为 n 个整数 h1,h2,. . . ,hn。
输出格式
输出共一行,一个整数代表答案。
样例输入
4 1 1 4 5 6 49
样例输出
18
提示
【样例说明】将第四座山变为 ⌊√49⌋ = 7,然后再将第四座山变为 ⌊7/2⌋ = 3。体力值为 4 + 5 + 6 + 3 = 18。
【评测用例规模与约定】
对于 20% 的评测用例,保证 n ≤ 8,P = 0。
对于 100% 的评测用例,保证 n ≤ 100000,0 ≤ P ≤ n,0 ≤ Q ≤ n,0 ≤ hi ≤ 100000。
#include <iostream>
#include<vector>
#include <cmath>
#include <queue>
using namespace std;
int main()
{
int n, p, q;
cin >> n >> p >> q;
priority_queue<int> qq;
for (int i = 0; i < n; i++)
{
int x;
cin >> x;
qq.push(x);
}
while (p > 0 || q > 0)
{
int y = qq.top();
qq.pop();
if (y > 4 && p > 0)
{
y = sqrt(y);
qq.push(y);
p--;
}
else if (y > 4 && p == 0)
{
y = y / 2;
qq.push(y);
q--;
}
else if (y < 4 && q > 0)
{
y = y / 2;
qq.push(y);
q--;
}
else
{
y = sqrt(y);
qq.push(y);
p--;
}
}
int sum = 0;
while (!qq.empty())
{
sum += qq.top();
qq.pop();
}
cout << sum;
return 0;
}
试题H:拔河
题目描述
小明是学校里的一名老师,他带的班级共有 n 名同学,第 i 名同学力量值为 ai。在闲暇之余,小明决定在班级里组织一场拔河比赛。
为了保证比赛的双方实力尽可能相近,需要在这 n 名同学中挑选出两个队伍,队伍内的同学编号连续:{al1, al1+1, ..., ar1−1, ar1} 和 {al2, al2+1, ..., ar2−1, ar2},其中 l1 ≤ r1 < l2 ≤ r2。
两个队伍的人数不必相同,但是需要让队伍内的同学们的力量值之和尽可能相近。请计算出力量值之和差距最小的挑选队伍的方式。
输入格式
输入共两行。
第一行为一个正整数 n。
第二行为 n 个正整数 ai。
输出格式
输出共一行,一个非负整数,表示两个队伍力量值之和的最小差距。
样例输入
5 10 9 8 12 14
样例输出
1
#include <iostream>
#include<vector>
#include <cmath>
#include <queue>
#include<algorithm>
#include <set>
using namespace std;
typedef long long ll;
int main()
{
int n;
cin >> n;
vector<long long> v(n+1);
vector<long long> sum(n+1);
multiset<ll> S;
ll mindiff = 9999999999;
for (int i = 1; i <= n; i++)
{
cin >> v[i];
sum[i] = sum[i - 1] + v[i];
}
for (int i = 1; i <= n; i++)
{
for (int j = i + 1; j <= n; j++)
{
S.insert(sum[j] - sum[i]);
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 0; j < i; j++)
{
ll x = sum[i] - sum[j];
auto it = S.lower_bound(x);
if (it != S.end())
{
mindiff = min(mindiff, abs(*it - x));
}
if (it != S.begin())
{
it--;
mindiff = min(mindiff, abs(*it - x));
}
}
for (int i2 = i + 1; i2 <= n; i2++)
{
S.erase(S.find(sum[i2] - sum[i]));
}
}
cout << mindiff;
return 0;
}
这道题目用的是前缀和以及二分查找算法,使用multiset存储各个区间的和,然后进行判断
这道题有两个重点
1.循环顺序
2.删除重复数据
这样能够防止区间出现重叠/交叉问题