GESP认证C++编程真题解析 | 202309 四级
欢迎大家订阅我的专栏:算法题解:C++与Python实现!
本专栏旨在帮助大家从基础到进阶 ,逐步提升编程能力,助力信息学竞赛备战!
专栏特色
1.经典算法练习:根据信息学竞赛大纲,精心挑选经典算法题目,提供清晰的代码实现与详细指导,帮助您夯实算法基础。
2.系统化学习路径:按照算法类别和难度分级,从基础到进阶,循序渐进,帮助您全面提升编程能力与算法思维。
适合人群:
- 准备参加蓝桥杯、GESP、CSP-J、CSP-S等信息学竞赛的学生
- 希望系统学习C++/Python编程的初学者
- 想要提升算法与编程能力的编程爱好者
附上汇总帖:GESP认证C++编程真题解析 | 汇总
编程题
B3869 进制转换
【题目来源】
洛谷:[B3869 GESP202309 四级] 进制转换 - 洛谷
【题目描述】
\(N\) 进制数指的是逢 \(N\) 进一的计数制。例如,人们日常生活中大多使用十进制计数,而计算机底层则一般使用二进制。除此之外,八进制和十六进制在一些场合也是常用的计数制(十六进制中,一般使用字母 A 至 F 表示十至十五;本题中,十一进制到十五进制也是类似的)。
在本题中,我们将给出 \(N\) 个不同进制的数。你需要分别把它们转换成十进制数。
【输入】
输入的第一行为一个十进制表示的整数 \(N\)。接下来 \(N\) 行,每行一个整数 \(K\),随后是一个空格,紧接着是一个 \(K\) 进制数,表示需要转换的数。保证所有 \(K\) 进制数均由数字和大写字母组成,且不以 \(0\) 开头。保证 \(K\) 进制数合法。
保证 \(N \le 1000\);保证 \(2 \le K \le 16\)。
保证所有 \(K\) 进制数的位数不超过 \(9\)。
【输出】
输出 \(N\) 行,每一个十进制数,表示对应 \(K\) 进制数的十进制数值。
【输入样例】
2
8 1362
16 3F0
【输出样例】
754
1008
【算法标签】
《洛谷 B3869 进制转换》 #进制# #GESP# #2023#
【代码详解】
#include <bits/stdc++.h>
using namespace std;
#define int long long // 使用长整型
int n; // 测试用例数量
/**
* 将指定进制的字符串转换为十进制整数
* 支持2-16进制
* @param x 进制(2-16)
* @param t 要转换的字符串
* @return 对应的十进制整数
*/
int calc(int x, string t)
{
int res = 0; // 存储转换结果
// 遍历字符串的每个字符
for (int i = 0; i < t.size(); i++)
{
if (t[i] <= '9')
{
// 处理数字字符 '0'-'9'
// 霍纳法则:res = res * 进制 + 当前位的值
res = res * x + (t[i] - '0');
}
else
{
// 处理字母字符 'A'-'F'
// 将'A'-'F'转换为10-15
res = res * x + (t[i] - 'A' + 10);
}
}
return res;
}
signed main() // 因为使用了#define int long long
{
// 输入测试用例数量
cin >> n;
// 处理每个测试用例
while (n--)
{
int k; // 进制
string s; // 要转换的字符串
cin >> k >> s;
// 调用calc函数进行进制转换并输出结果
cout << calc(k, s) << endl;
}
return 0;
}
【运行结果】
2
8 1362
754
16 3F0
1008
B3870 变长编码
【题目来源】
洛谷:[B3870 GESP202309 四级] 变长编码 - 洛谷
【题目描述】
小明刚刚学习了三种整数编码方式:原码、反码、补码,并了解到计算机存储整数通常使用补码。但他总是觉得,生活中很少用到 \(2^{31}-1\) 这么大的数,生活中常用的 \(0\sim 100\) 这种数也同样需要用 \(4\) 个字节的补码表示,太浪费了些。
热爱学习的小明通过搜索,发现了一种正整数的变长编码方式。这种编码方式的规则如下:
- 对于给定的正整数,首先将其表达为二进制形式。例如,\((0)_{\{10\}}=(0)_{\{2\}}\),\((926)_{\{10\}}=(1110011110)_{\{2\}}\)。
- 将二进制数从低位到高位切分成每组 \(7\) bit,不足 \(7\)bit 的在高位用 \(0\) 填补。例如,\((0)_{\{2\}}\) 变为\(0000000\) 的一组,\((1110011110)_{\{2\}}\) 变为 \(0011110\) 和 \(0000111\) 的两组。
- 由代表低位的组开始,为其加入最高位。如果这组是最后一组,则在最高位填上 \(0\),否则在最高位填上 \(1\)。于是,\(0\) 的变长编码为 \(00000000\) 一个字节, \(926\) 的变长编码为 \(10011110\) 和 \(00000111\) 两个字节。
这种编码方式可以用更少的字节表达比较小的数,也可以用很多的字节表达非常大的数。例如,\(987654321012345678\) 的二进制为 \((0001101 \ 1011010 \ 0110110 \ 1001011 \ 1110100 \ 0100110 \ 1001000 \ 0010110 \ 1001110)_{\{2\}}\),于是它的变长编码为(十六进制表示) CE 96 C8 A6 F4 CB B6 DA 0D,共 \(9\) 个字节。
你能通过编写程序,找到一个正整数的变长编码吗?
【输入】
输入第一行,包含一个正整数 \(N\)。约定 \(0\le N \le 10^{18}\)。
【输出】
输出一行,输出 \(N\) 对应的变长编码的每个字节,每个字节均以 \(2\) 位十六进制表示(其中, A-F 使用大写字母表示),两个字节间以空格分隔。
【输入样例】
0
【输出样例】
00
【算法标签】
《洛谷 B3870 变长编码》 #GESP# #2023#
【代码详解】
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1005;
int n;
string a[N]; // 存储分组后的二进制字符串
/**
* 十进制转二进制字符串
* @param x 十进制整数
* @return 二进制字符串
*/
string DtoB(int x)
{
string d = "0123456789ABCDEF"; // 数字字符表
string ans = "";
// 不断除以2,取余数
while (x > 0)
{
ans = d[x % 2] + ans; // 余数转换为'0'或'1',加到字符串前面
x /= 2;
}
return ans;
}
/**
* 二进制字符串转十进制
* @param s 二进制字符串
* @return 十进制整数
*/
int BtoD(string s)
{
int ans = 0;
// 使用霍纳法则:ans = ans * 2 + 当前位
for (int i = 0; i < s.size(); i++)
{
ans = ans * 2 + (s[i] - '0');
}
return ans;
}
/**
* 十进制转十六进制字符串
* @param x 十进制整数
* @return 十六进制字符串(至少两位,不足补0)
*/
string DtoH(long long x)
{
string d = "0123456789ABCDEF", ans = "";
// 特判0的情况
if (x == 0)
{
return "0"; // 注意:这里返回"0",但下面有补0处理
}
// 不断除以16,取余数
while (x > 0)
{
ans = d[x % 16] + ans; // 余数转换为十六进制字符
x /= 16;
}
// 如果结果只有一位,前面补0
if (ans.length() == 1)
{
ans = "0" + ans;
}
return ans;
}
signed main()
{
cin >> n;
// 特判输入为0的情况
if (n == 0)
{
cout << "00" << endl;
return 0;
}
// 1. 十进制转二进制
string s = DtoB(n);
// 2. 从低位到高位,每7位一组(最后一组可能不足7位)
int cnt = 0; // 当前组内计数
int cur = 1; // 当前组号
for (int i = s.size() - 1; i >= 0; i--) // 从低位(字符串末尾)开始
{
cnt++;
a[cur] += s[i]; // 将当前位添加到当前组
// 每7位一组
if (cnt == 7)
{
cur++; // 开始新的一组
cnt = 0;
}
}
// 3. 最后一组如果不足7位,用0补齐
while (a[cur].size() < 7)
{
a[cur] += '0';
}
// 4. 为每组添加最高位(标识位)
for (int i = 1; i < cur; i++) // 前cur-1组,最高位为1(表示还有后续)
{
a[i] += '1';
}
a[cur] += '0'; // 最后一组,最高位为0(表示结束)
// 5. 反转每组字符串(因为是从低位开始构建的)
for (int i = 1; i <= cur; i++)
{
reverse(a[i].begin(), a[i].end());
}
// 6. 将每组8位二进制转换为十六进制输出
for (int i = 1; i <= cur; i++)
{
int t = BtoD(a[i]); // 二进制转十进制
// cout << "t " << t << endl;
string s = DtoH(t); // 十进制转十六进制
cout << s << " "; // 输出十六进制,以空格分隔
}
return 0;
}
【运行结果】
0
00

浙公网安备 33010602011771号