GESP 四级题单
- [GESP202309 四级] 变长编码
- 题目描述
- 输入格式
- 输出格式
- 样例 #1
- 样例输入 #1
- 样例输出 #1
- 样例 #2
- 样例输入 #2
- 样例输出 #2
- 样例 #3
- 样例输入 #3
- 样例输出 #3
- 参考答案
- 代码解析
- [GESP202403 四级] 做题
- 题目描述
- 输入格式
- 输出格式
- 样例 #1
- 样例输入 #1
- 样例输出 #1
- 提示
- 数据规模与约定
- 参考答案
- 代码解析
- [GESP202312 四级] 田忌赛马
- 题目描述
- 输入格式
- 输出格式
- 样例 #1
- 样例输入 #1
- 样例输出 #1
- 样例 #2
- 样例输入 #2
- 样例输出 #2
- 提示
- 参考答案
- [GESP202306 四级] 幸运数
- 题目描述
- 输入格式
- 输出格式
- 样例 #1
- 样例输入 #1
- 样例输出 #1
- 提示
- 参考答案
- [GESP202306 四级] 图像压缩
- 题目描述
- 输入格式
- 输出格式
- 样例 #1
- 样例输入 #1
- 样例输出 #1
- 提示
- 参考答案
[GESP202309 四级] 变长编码
题目描述
小明刚刚学习了三种整数编码方式:原码、反码、补码,并了解到计算机存储整数通常使用补码。但他总是觉得,生活中很少用到 2 31 − 1 2^{31}-1 231−1 这么大的数,生活中常用的 0 ∼ 100 0\sim 100 0∼100 这种数也同样需要用 4 4 4 个字节的补码表示,太浪费了些。
热爱学习的小明通过搜索,发现了一种正整数的变长编码方式。这种编码方式的规则如下:
-
对于给定的正整数,首先将其表达为二进制形式。例如, ( 0 ) { 10 } = ( 0 ) { 2 } (0)_{\{10\}}=(0)_{\{2\}} (0){10}=(0){2}, ( 926 ) { 10 } = ( 1110011110 ) { 2 } (926)_{\{10\}}=(1110011110)_{\{2\}} (926){10}=(1110011110){2}。
-
将二进制数从低位到高位切分成每组 7 7 7 bit,不足 7 7 7bit 的在高位用 0 0 0 填补。例如, ( 0 ) { 2 } (0)_{\{2\}} (0){2} 变为 0000000 0000000 0000000 的一组, ( 1110011110 ) { 2 } (1110011110)_{\{2\}} (1110011110){2} 变为 0011110 0011110 0011110 和 0000111 0000111 0000111 的两组。
-
由代表低位的组开始,为其加入最高位。如果这组是最后一组,则在最高位填上 0 0 0,否则在最高位填上 1 1 1。于是, 0 0 0 的变长编码为 00000000 00000000 00000000 一个字节, 926 926 926 的变长编码为 10011110 10011110 10011110 和 00000111 00000111 00000111 两个字节。
这种编码方式可以用更少的字节表达比较小的数,也可以用很多的字节表达非常大的数。例如, 987654321012345678 987654321012345678 987654321012345678 的二进制为 ( 0001101 1011010 0110110 1001011 1110100 0100110 1001000 0010110 1001110 ) { 2 } (0001101 \ 1011010 \ 0110110 \ 1001011 \ 1110100 \ 0100110 \ 1001000 \ 0010110 \ 1001110)_{\{2\}} (0001101 1011010 0110110 1001011 1110100 0100110 1001000 0010110 1001110){2},于是它的变长编码为(十六进制表示) CE 96 C8 A6 F4 CB B6 DA 0D
,共 9 9 9 个字节。
你能通过编写程序,找到一个正整数的变长编码吗?
输入格式
输入第一行,包含一个正整数 N N N。约定 0 ≤ N ≤ 1 0 18 0\le N \le 10^{18} 0≤N≤1018。
输出格式
输出一行,输出 N N N 对应的变长编码的每个字节,每个字节均以 2 2 2 位十六进制表示(其中, A-F
使用大写字母表示),两个字节间以空格分隔。
样例 #1
样例输入 #1
0
样例输出 #1
00
样例 #2
样例输入 #2
926
样例输出 #2
9E 07
样例 #3
样例输入 #3
987654321012345678
样例输出 #3
CE 96 C8 A6 F4 CB B6 DA 0D
参考答案
// longCode.cpp
// 字符串、进制
#include <iostream>
using namespace std;long long n;
string h = "0123456789ABCDEF";void p(int i)
{cout << h[i/16] << h[i%16] << " ";
}int main()
{// 输入cin >> n;// 特例if (n == 0){cout << "00";return 0;}// 模拟while(n){int k = n % 128;n /= 128;if (n > 0){p(k+128); // 判断是否为最高位}else{p(k);}}return 0;
}
代码解析
128 128 128 表示 2 7 2^7 27,因为我们一般七位分隔一次。
在 while
循环内部,首先使用取余操作 n % 128
得到当前位的十进制值,并保存在变量 k
中。然后使用除法操作 n /= 128
得到下一位的十进制值。这样,循环会逐步将整数 n
从右向左进行拆解,直到 n
变为 0 0 0 为止。
在执行完除法操作后,会判断当前位是否是最高位。如果 n > 0
成立,说明还有更高位的值需要处理,此时将 k+128
传入函数 p()
,函数 p()
会将该值转换成十六进制字符输出。否则,直接将 k
传入函数 p()
,将当前位的值转换成十六进制字符输出。
[GESP202403 四级] 做题
题目描述
小杨同学为了提高自己的实力制定了做题计划,在第 k k k 天时,他必须要完成 k k k 道题,否则他就会偷懒。
小杨同学现在找到了一个题库,一共有 n n n 套题单,每一套题单中有一定数量的题目。但是他十分挑剔,每套题单他只会使用一次,每一天也只能使用一套题单里的题目,之后那套题单就会弃之不用。对于每套题单,他不必完成题单内所有的题。
那么问题来了,小杨同学最多做题几天才偷懒呢?
输入格式
第一行,一个整数为 n n n,表示有多少套题单。
第二行 n n n 个整数 a 1 , a 2 , … a n a_1, a_2, \dots a_n a1,a2,…an,分别表示每套题单有多少道题。
输出格式
输出一行一个整数表示答案。
样例 #1
样例输入 #1
4
3 1 4 1
样例输出 #1
3
提示
数据规模与约定
对全部的测试数据,保证 1 ≤ n ≤ 1 0 6 1 \leq n \leq 10^6 1≤n≤106, 1 ≤ a i ≤ 1 0 9 1 \leq a_i \leq 10^9 1≤ai≤109。
参考答案
// doTask.cpp
// 贪心
#include <iostream>
#include <algorithm>
using namespace std;int n;
int a[1000010];
int sum = 1;int main()
{// 输入cin >> n;for (int i = 1; i <= n; i++){cin >> a[i];}// 排序 + 贪心sort(a+1, a+n+1);for (int i = 1; i <= n; i++){if (a[i] < sum) continue;else sum++;}// 输出cout << sum-1;return 0;
}
代码解析
- 将题单的题目数量进行排序
- 遍历题单:
- 如果题单里的题目数量小于等于当前的天数:
- 是:小杨同学可以完成这个题单
- 否:小杨同学会偷懒
- 如果题单里的题目数量小于等于当前的天数:
- 最多偷懒的天数是指小杨同学可以不做题的最长连续天数,所以最后输出要 − 1 -1 −1。
[GESP202312 四级] 田忌赛马
题目描述
你要和田忌赛马。你们各自有 N N N 匹马,并且要进行 N N N 轮比赛,每轮比赛,你们都要各派出一匹马决出胜负。
你的马匹的速度分别为 u 1 , u 2 , ⋯ , u n u_1,u_2,\cdots,u_n u1,u2,⋯,un,田忌的马匹的速度分别为 v 1 , v 2 , ⋯ , v n v_1,v_2,\cdots,v_n v1,v2,⋯,vn。田忌会按顺序派出他的马匹,请问你要如何排兵布阵,才能赢得最多轮次的比赛?巧合的是,你和田忌的所有马匹的速度两两不同,因此不可能出现平局。
输入格式
第一行一个整数 N N N。保证 1 ≤ N ≤ 5 × 1 0 4 1\le N \le 5\times 10^4 1≤N≤5×104
接下来一行 N N N 个用空格隔开的整数,依次为 u 1 , u 2 , ⋯ , u n u_1,u_2,\cdots,u_n u1,u2,⋯,un,表示你的马匹们的速度。保证 1 ≤ u i ≤ 2 N 1\le u_i\le 2N 1≤ui≤2N。
接下来一行 N N N 个用空格隔开的整数,依次为 v 1 , v 2 , ⋯ , v n v_1,v_2,\cdots,v_n v1,v2,⋯,vn,表示田忌的马匹们的速度。保证 1 ≤ v i ≤ 2 N 1\le v_i\le 2N 1≤vi≤2N。
输出格式
输出一行,表示你最多能获胜几轮。
样例 #1
样例输入 #1
3
1 3 5
2 4 6
样例输出 #1
2
样例 #2
样例输入 #2
5
10 3 5 8 7
4 6 1 2 9
样例输出 #2
5
提示
样例解释 1
第 1 轮,田忌派出速度为 2 的马匹,你可以派出速度为 3 的马匹迎战,本轮你获胜。
第 2 轮,田忌派出速度为 4 的马匹,你可以派出速度为 5 的马匹迎战,本轮你获胜。
第 3 轮,田忌派出速度为 6 的马匹,你可以派出速度为 1 的马匹迎战,本轮田忌获胜。
如此,你可以赢得 2 轮比赛。
参考答案
// horseRacing.cpp
// 双指针、贪心
#include <iostream>
#include <algorithm>
using namespace std;int n; // 马匹数量
int ans; // 最多赢的轮数
int l = 1, r = 1; // 左右指针
int a[500005]; // 你的马匹速度
int b[500005]; // 田忌马匹速度int main()
{// 输入cin >> n;for (int i = 1; i <= n; i++){cin >> a[i];}for (int i = 1; i <= n; i++){cin >> b[i];}// 排序sort(a+1, a+n+1);sort(b+1, b+n+1);// 贪心ans = n;while (l <= n && r <= n) // 保证指针在范围内{if (a[r] <= b[l]) // 你的马匹速度<=田忌的速度{r++; // 你的马匹指针右移ans--; // 胜场数减少}else // 你的马匹速度>田忌的速度{r++; // 你的马匹指针右移l++; // 田忌的马匹指针右移}}// 输出cout << ans;return 0;
}
[GESP202306 四级] 幸运数
题目描述
小明发明了一种 “幸运数”。一个正整数,其偶数位不变(个位为第 1 1 1 位,十位为第 2 2 2 位,以此类推),奇数位做如下变换:将数字乘以 7 7 7,如果不大于 9 9 9 则作为变换结果,否则把结果的各位数相加,如果结果不大于 9 9 9 则作为变换结果,否则(结果仍大于 9 9 9)继续把各位数相加,直到结果不大于 9 9 9,作为变换结果。变换结束后,把变换结果的各位数相加,如果得到的和是 8 8 8 的倍数,则称一开始的正整数为幸运数。
例如, 16347 16347 16347:第 1 1 1 位为 7 7 7,乘以 7 7 7 结果为 49 49 49,大于 9 9 9,各位数相加为 13 13 13,仍大于 9 9 9,继续各位数相加,最后结果为 4 4 4;第 3 3 3 位为 3 3 3,变换结果为 3 3 3;第 5 5 5 位为 1 1 1,变换结果为 7 7 7。最后变化结果为 76344 76344 76344,对于结果 76344 76344 76344 其各位数之和为 24 24 24,是 8 8 8 的倍数。因此 16347 16347 16347 是幸运数。
输入格式
输入第一行为正整数 N N N,表示有 N N N 个待判断的正整数。约定 1 ≤ N ≤ 20 1 \le N \le 20 1≤N≤20。
从第 2 2 2 行开始的 N N N 行,每行一个正整数,为待判断的正整数。约定这些正整数小于 1 0 12 10^{12} 1012。
输出格式
输出 N N N 行,对应 N N N 个正整数是否为幸运数,如是则输出 ‘T’,否则输出 ‘F’。
提示:不需要等到所有输入结束在依次输出,可以输入一个数就判断一个数并输出,再输入下一个数。
样例 #1
样例输入 #1
2
16347
76344
样例输出 #1
T
F
提示
算法核心思想:
- 将正整数进行数位分离
- 对于偶数位上的数字,保持不变。
- 对于奇数位上的数字,将它 × 7 \times7 ×7,并将结果各位数相加,直到结果 ≤ 9 \le9 ≤9。
- 判断和是否是 8 8 8 的倍数,如果是,a则为幸运数;否则,不是幸运数。
参考答案
#include <iostream>
using namespace std;int T;
long long n;int trans(long long k)
{k *= 7;while (k > 9){int ans = 0;while (k){ans += k % 10;k /= 10;}k = ans;}return k;
}bool judge(long long n)
{int ans = 0;for (int p = 1; n; n /= 10, ++p){if (p & 1) ans += trans(n % 10);else ans += n % 10;}return !(ans % 8);
}int main()
{cin >> T;for (int i = 1; i <= T; i++){cin >> n;cout << (judge(n) ? 'T' : 'F') << endl;}return 0;
}
[GESP202306 四级] 图像压缩
题目描述
图像是由很多的像素点组成的。如果用 0 0 0 表示黑, 255 255 255 表示白, 0 0 0 和 255 255 255 之间的值代表不同程度的灰色,则可以用一个字节表达一个像素(取值范围为十进制 0-255
、十六进制 00-FF
)。这样的像素组成的图像,称为 256 256 256 级灰阶的灰度图像。
现在希望将 256 256 256 级灰阶的灰度图像压缩为 16 16 16 级灰阶,即每个像素的取值范围为十进制 0-15
、十六进制 0-F
。压缩规则为:统计出每种灰阶的数量,取数量最多的前 16 16 16 种灰阶(如某种灰阶的数量与另外一种灰阶的数量相同,则以灰阶值从小到大为序),分别编号 0-F
(最多的编号为 0
,以此类推)。其他灰阶转换到最近的 16 16 16 种灰阶之一,将某个点的灰阶值(灰度,而非次数)与 16 16 16 种灰阶中的一种相减,绝对值最小即为最近,如果绝对值相等,则编号较小的灰阶更近。
输入格式
输入第 1 1 1 行为一个正整数 n ( 10 ≤ n ≤ 20 ) n(10\le n \le 20) n(10≤n≤20),表示接下来有 n n n 行数据组成一副 256 256 256 级灰阶的灰度图像。
第 2 2 2 行开始的 n n n 行,每行为长度相等且为偶数的字符串,每两个字符用十六进制表示一个像素。约定输入的灰度图像至少有 16 16 16 种灰阶。约定每行最多 20 20 20 个像素。
输出格式
第一行输出压缩选定的 16 16 16 种灰阶的十六进制编码,共计 32 32 32 个字符。
第二行开始的 n n n 行,输出压缩后的图像,每个像素一位十六进制数表示压缩后的灰阶值。
样例 #1
样例输入 #1
10
00FFCFAB00FFAC09071B5CCFAB76
00AFCBAB11FFAB09981D34CFAF56
01BFCEAB00FFAC0907F25FCFBA65
10FBCBAB11FFAB09981DF4CFCA67
00FFCBFB00FFAC0907A25CCFFC76
00FFCBAB1CFFCB09FC1AC4CFCF67
01FCCBAB00FFAC0F071A54CFBA65
10EFCBAB11FFAB09981B34CFCF67
01FFCBAB00FFAC0F071054CFAC76
1000CBAB11FFAB0A981B84CFCF66
样例输出 #1
ABCFFF00CB09AC07101198011B6776FC
321032657CD10E
36409205ACC16D
B41032657FD16D
8F409205ACF14D
324F326570D1FE
3240C245FC411D
BF4032687CD16D
8F409205ACC11D
B240326878D16E
83409205ACE11D
提示
【样例 1 1 1 解释】
灰阶 AB
、CF
和 FF
出现 14 14 14 次,00
出现 10 10 10 次,CB
出现
9 9 9 次,09
出现 7 7 7 次,AC
出现 6 6 6 次,07
出现 5 5 5 次,10
、11
和 98
出现 4 4 4 次,01
、1B
、67
、76
和 FC
出现 3 3 3 次。
算法核心思想:
- 记录每种灰阶的出现次数
- 灰阶按照出现次数从大到小排序,判断出现次数是否有相同:
- 有则按照灰阶值从小到大排序
- 取出前 16 16 16 个灰阶作为压缩选定的灰阶
- 遍历压缩选定的灰阶
- 计算每个压缩灰阶与当前像素的差值的绝对值,找到最小的差值对应的压缩灰阶
- 将这个压缩灰阶的索引转换为十六进制表示,并输出到压缩后的图像中
参考答案
// 没有做出来真的不怪大家,题目太难了,而且是最恶心的模拟
#include <iostream>
#include <vector>
#include <algorithm>
const int N = 30;
using namespace std;struct Node
{int tot, g;friend bool operator < (Node a, Node b){return a.tot != b.tot ? a.tot > b.tot : a.g < b.g;}
};int n;
Node a[300];
vector <pair <int, char> > mm;
int pic[100][100];int main()
{ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);cin >> n;int m = n;int len;for (int i = 1; i <= n; i++){string s;cin >> s;len = s.size();for (int j = 0; j < s.size(); j += 2){int cnt = (s[j] > '9' ? s[j] - 'A' + 10 : s[j] - '0') * 16 + (s[j + 1] > '9' ? s[j + 1] - 'A' + 10 : s[j + 1] - '0');a[cnt].tot++, a[cnt].g = cnt;pic[i][j / 2 + 1] = cnt;}}sort(a, a+299);for (int i = 0; i < 16; i++){cout << char(a[i].g / 16 > 9 ? a[i].g / 16 - 10 + 'A' : a[i].g / 16 + '0');cout << char(a[i].g % 16 > 9 ? a[i].g % 16 - 10 + 'A' : a[i].g % 16 + '0');}cout << endl;for (int i = 1; i <= m; i++){for (int j = 1; j <= len / 2; j++){int mina = 300;char c;for (int k = 0; k < 16; k++){if (abs(a[k].g - pic[i][j]) < mina){mina = abs(a[k].g - pic[i][j]), c = (k > 9 ? k - 10 + 'A' : k + '0');}}cout << c;}cout << endl;}return 0;
}