CCF编程能力等级认证GESP—C++4级—20230923
单选题(每题 2 分,共 30 分)
1、⼈们所使用的手机上安装的App通常指的是( )。
A.⼀款操作系统
B.⼀款应用软件
C.⼀种通话设备
D.以上都不对
正确答案:B
A选项:这个选项不正确。操作系统是手机或计算机的基础软件,它负责管理和控制硬件和软件资源,提供用户界面,以及支持其他应用程序的运行。常见的手机操作系统有Android、iOS等。而手机上安装的App是运行在操作系统之上的应用软件,不是操作系统本身。
B选项:这个选项是正确的。手机上安装的App通常指的是一款应用软件。应用软件是为了满足特定需求而开发的程序,可以执行各种任务,如社交、娱乐、购物、学习等。用户可以从应用商店下载和安装这些应用软件,并在手机上运行它们。
C选项:这个选项也不正确。通话设备是指手机本身或其硬件组件,用于实现通话功能,如麦克风、扬声器和通信模块等。而手机上安装的App是软件层面的应用程序,与通话设备的硬件属性不同。
D选项:由于B选项是正确的,所以D选项“以上都不对”自然是不正确的。
综上所述,手机上安装的App指的是一款应用软件,因此正确答案是B。这些应用软件可以提供各种功能和服务,丰富手机的使用体验,并满足用户的多样化需求。
2、下列流程图的输出结果是?( )
A. 9
B. 7
C. 5
D. 11
正确答案:A
m = 1, n = 1
m * n > 20 | m | n | n > 5 |
---|---|---|---|
false | 3 | 2 | false |
false | 7 | 3 | false |
true | 5 | 4 | false |
false | 11 | 5 | false |
true | 9 | 6 | true |
3、对包含n个元素的数组进⾏冒泡排序 ,平均时间复杂度一般为( )。
A.
O
(
n
)
O(n)
O(n)
B.
O
(
n
l
o
g
n
)
O(n log n)
O(nlogn)
C.
O
(
n
2
)
O(n^2)
O(n2)
D.以上都不正确
正确答案:C
对包含n个元素的数组进行冒泡排序时,平均时间复杂度一般为 O ( n 2 ) O(n^2) O(n2)。冒泡排序的基本思想是重复地遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。遍历数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。
最好情况:输入数组已经有序,此时只需要进行一次遍历,时间复杂度为O(n)。
最坏情况:输入数组完全逆序,此时需要进行n−1次遍历,每次遍历都需要比较n−i次(i为当前遍历的次数),因此总比较次数为 ( n − 1 ) + ( n − 2 ) + … + 2 + 1 = n ( n − 1 ) 2 (n−1)+(n−2)+…+2+1= \frac{n(n-1)}{2} (n−1)+(n−2)+…+2+1=2n(n−1) ,时间复杂度为 O ( n 2 ) O(n^2) O(n2)。
平均情况:由于冒泡排序在数据随机分布的情况下,大约有一半的时间处于最好情况,一半的时间处于最坏情况,因此平均时间复杂度也是 O ( n 2 ) O(n^2) O(n2)
4、下列关于C++语⾔中指针的叙述 ,不正确的是( )。
A.可以定义指向int类型的指针。
B.可以定义指向⾃定义结构体类型的指针。
C.⾃定义结构体类型可以包含指针类型的元素。
D.不能定义指向void类型的指针 ,那没有意义。
正确答案:D
A选项:我们可以定义指向任何基本数据类型(如int)的指针。例如:
int x = 10;
int* ptr = &x; // ptr是指向int类型的指针
B选项:在C++中,我们可以定义指向自定义结构体类型的指针。例如:
struct MyStruct {
int a;
double b;
};
MyStruct s;
MyStruct* ptr = &s; // ptr是指向MyStruct类型的指针
C选项:在C++中,结构体可以包含任何类型的成员,包括指针。例如:
struct MyStruct {
int* ptrToInt; // MyStruct包含一个指向int的指针
};
D选项:这是不正确的。在C++中,我们可以定义指向void类型的指针,这种指针被称为void指针。void指针可以指向任何类型的数据,但在使用之前必须将其转换为适当的类型。void指针在某些情况下是有用的,例如,在函数中可以使用void指针作为通用指针,然后在函数内部根据需要进行类型转换。例如:
#include <iostream>
using namespace std;
int main() {
void* ptr = nullptr; // 定义一个void指针
int x = 10;
ptr = &x; // void指针指向int
// 在解引用之前进行类型转换
int* intPtr = static_cast<int*>(ptr);
cout << "The value of x is: " << *intPtr << endl;
double y = 3.14;
ptr = &y; // void指针指向double
// 在解引用之前进行类型转换
double* doublePtr = static_cast<double*>(ptr);
cout << "The value of y is: " << *doublePtr << endl;
return 0;
}
在这个例子中,我们首先定义了一个int类型的变量x并初始化为42。然后,我们定义了一个void指针ptr,并将它指向x的地址。接下来,我们使用static_cast将void指针ptr转换为int指针intPtr。最后,我们通过解引用intPtr来访问x的值,并将其打印到控制台。
注意,使用static_cast进行转换是安全的,前提是你确实知道void指针原本指向的数据类型。如果你错误地将void指针转换为不匹配的类型,那么解引用该指针将会导致未定义行为,通常是程序崩溃或数据损坏。因此,确保转换的正确性是非常重要的。
此外,还有其他类型的转换,如reinterpret_cast,它提供了更宽松的转换规则,但使用时需要格外小心,因为它可能导致类型安全问题。在大多数情况下,static_cast是首选的转换方式,因为它提供了更强的类型检查。
5、下列关于C++语⾔中数组的叙述 ,不正确的是( )。
A.一维数组可以用来表示数列。
B.二维数组可以用来表示矩阵。
C.三维数组可以用来表示空间中物体的形状。
D.世界是三维的 ,所以定义四维数组没有意义。
正确答案:D
A选项:这是正确的。一维数组在C++中通常用于存储一系列相同类型的元素,这些元素按照线性顺序排列,因此可以很方便地用来表示数列。
B选项:这也是正确的。二维数组在C++中用于存储二维数据,即数据以行和列的形式组织,非常适合用来表示数学中的矩阵。
C选项:这个叙述也是正确的。虽然三维数组本身并不直接表示物体的形状,但它可以用来存储与三维空间相关的数据,比如体素(voxel)数据,或者用于某些计算几何的算法中。因此,可以说三维数组在某些情况下可以用来间接表示空间中物体的形状或结构。
D选项:这个叙述是不正确的。世界确实是三维的,但这并不意味着定义四维数组就没有意义。在计算机科学和数学中,四维数组(或更高维度的数组)有多种用途。例如,在物理学中,四维时空是一个重要的概念;在机器学习和数据科学中,高维数组(包括四维数组)用于存储和处理多维数据;在图像处理中,四维数组可以用来表示带有时间维度的视频数据。因此,定义四维数组是有意义的,并且在实际应用中有着广泛的用途。
6、下列关于C++语⾔中函数的叙述 ,正确的是( )。
A.函数调用前必须定义。
B.函数调用时必须提供足够的实际参数。
C.函数定义前必须声明。
D.函数声明只能写在函数调用前。
正确答案:B
A选项:这个叙述是不正确的。在C++中,你可以在调用函数之前声明它,然后在后面的代码中定义它。这通常是通过函数原型(也称为函数声明)来实现的,它告诉编译器函数的名称、返回类型以及它接受的参数类型。
B选项:这个叙述是正确的。当你调用一个函数时,你必须提供与函数定义中声明的参数类型和数量相匹配的实际参数。如果提供的参数不足或类型不匹配,编译器会报错。
C选项:这个叙述是不正确的。在C++中,你可以在定义函数之前不声明它,只要你在调用它之前已经定义了它。然而,为了良好的编程实践和代码可读性,通常建议在函数定义之前先声明它(即使用函数原型)。
D选项:这个叙述也是不正确的。函数声明(或原型)可以出现在代码中的任何位置,只要它在任何对该函数的调用之前被编译器看到。这意味着你可以将函数声明放在文件的顶部,或者在需要之前立即声明它。
7、下列关于C++语⾔中函数的叙述 ,不正确的是( )。
A.两个函数的声明可以相同。
B.两个函数的局部变量可以重名。
C.两个函数的参数可以重名。
D.两个函数可以重名。
正确答案:A
A选项:这个叙述是不正确的。在C++中,函数的声明(也称为函数原型)必须唯一标识一个函数。这包括函数的返回类型、函数名以及参数列表(包括参数类型和数量)。如果两个函数的声明完全相同,那么它们实际上是同一个函数的两个声明,而不是两个不同的函数。
B选项:这个叙述是正确的。在C++中,每个函数都有自己的局部作用域,这意味着在一个函数中定义的局部变量不会与另一个函数中的局部变量冲突,即使它们的名字相同。
C选项:这个叙述也是正确的,但需要注意上下文。在同一个函数内部,参数名必须是唯一的,不能有两个同名的参数。但是,在不同的函数中,可以有同名的参数,因为每个函数的参数都是在其自己的作用域内定义的。
D选项:这个叙述在某种情况下是正确的,但通常带有一些限制。在C++中,通过函数重载(function overloading)可以实现具有相同名称但不同参数列表(类型、数量或顺序)的多个函数。然而,如果两个函数具有完全相同的参数列表,那么它们就不能仅仅通过重名来区分,因此这种情况下的重名是不允许的。
#include <iostream>
using namespace std;
// 第一个函数,没有参数
void foo() {
cout << "foo() called (no arguments)" << endl;
}
// 第二个函数,接受一个整数参数
void foo(int x) {
cout << "foo() called with argument: " << x << endl;
}
// 第三个函数,接受两个整数参数
void foo(int x, int y) {
cout << "foo() called with two arguments: " << x << ", " << y << endl;
}
int main() {
// 调用没有参数的foo函数
foo();
// 调用接受一个参数的foo函数
foo(42);
// 调用接受两个参数的foo函数
foo(10, 20);
return 0;
}
/*
foo() called (no arguments)
foo() called with argument: 42
foo() called with two arguments: 10, 20
*/
8、⼀个二维数组定义为 char array[3][10]; ,则这个二维数组占用内存的大小为( )。
A. 10
B. 30
C. 32
D. 48
正确答案:B
在C++中,二维数组char array[3][10];定义了一个包含3行10列的字符数组。每个字符在内存中占用1个字节。因此,整个数组占用的内存大小可以通过计算所有元素的总数来得出。
数组的总元素数是行数乘以列数,即3 * 10 = 30。因为每个元素(字符)占用1个字节,所以整个数组占用的内存大小是30 * 1 = 30字节。
9、如果n为int类型的变量,⼀个指针变量定义为int *p = &n; ,则下列说法正确的是( )。
A.指针变量p的值与变量n是相同
B.指针变量p的值与变量n的地址是相同的。
C.指针变量p指向的值为 'n'。
D.指针变量p指向的值与变量n的地址是相同的。
正确答案:B
A选项:这是不正确的。指针变量p的值是变量n的地址,而不是n的值。
B选项:这是正确的。int *p = &n;
这行代码将变量n的地址赋给了指针p,所以p的值就是n的地址。
C选项:这是不正确的。首先,‘n’是一个字符常量,而n是一个int类型的变量。其次,p指向的值是n的值,而不是字符’n’。
D选项:这是不正确的。p指向的值是n的值,而n的地址是p的值。这两者是不同的。
10、⼀个三维数组定义为 long long array[6][6][6]; ,则array[1][2][3]和array[3][2][1]在内存中的 位置相差多少字节?( )
A. 70字节
B. 198字节
C. 560字节
D.无法确定
正确答案:C
对于一个三维数组long long array[6][6][6];
,首先我们需要知道long long
类型占用8个字节。数组array
在内存中是按照连续的内存块存储的。array[i][j][k]
的内存位置可以通过以下公式计算:内存位置 = base_address + (i * 6 * 6 + j * 6 + k) * sizeof(long long)
其中base_address
是数组array
的起始地址,i
、j
、k
分别是三维数组的索引,sizeof(long long)
是long long
类型的大小(通常是8字节)。
现在,我们来计算array[1][2][3]
和array[3][2][1]
在内存中的位置差:
对于array[1][2][3]
:内存位置 = base_address + (1 * 6 * 6 + 2 * 6 + 3) * 8
对于array[3][2][1]
:内存位置 = base_address + (3 * 6 * 6 + 2 * 6 + 1) * 8
位置差就是两者内存位置的差值:位置差 = ((3 * 6 * 6 + 2 * 6 + 1) - (1 * 6 * 6 + 2 * 6 + 3)) * 8
计算这个差值,我们得到:位置差 = (108 + 12 + 1 - 36 - 12 - 3) * 8 = 70 * 8 = 560 字节
11、如果 a 为 int 类型的变量,且 a 的值为6,则执⾏a = ~a; 之后,a的值会是( )。
A. -6
B. 6
C. -7
D. 7
正确答案:C
在C++中,~是一个按位取反运算符,它会对操作数的每一位进行取反。对于int类型的变量,这通常意味着将变量的二进制表示中的每一位从0变为1,从1变为0。
操作 | a |
---|---|
二进制a | 0000 0110 |
~a | 1111 1001 |
反码 | 1111 1000 |
原码 | 1000 0111(-7) |
12、⼀个数组定义为int a[5] = {1, 2, 3, 4, 5}; ,⼀个指针定义为int * p = &a[2]; ,则执⾏*p = a[1]; 后 ,数组a中的值会变为( )。
A. {1, 2, 2, 4, 5}
B. {1, 3, 3, 4, 5}
C. {1, 2, 3, 3, 5}
D. {1, 2, 4, 4, 5}
正确答案:A
首先,我们有一个数组a
,其定义和初始化为:int a[5] = {1, 2, 3, 4, 5};
接下来,我们有一个指针p
,它被初始化为指向数组a
的第三个元素(即a[2]
):int *p = &a[2];
此时,p
指向a[2]
,即它存储了a[2]
的地址。
然后,我们执行以下操作:*p = a[1];
这里,*p
表示指针p
所指向的值,即a[2]
的值。我们将a[1]
的值(即2)赋给*p
,
因此a[2]
的值现在变为2。所以,执行上述操作后,数组a
中的值变为:a[0] = 1a[1] = 2a[2] = 2
13、下列关于C++语言中异常处理的叙述,正确的是( )。
A.⼀个try⼦句可以有多个catch⼦句与之对应。
B.如果try⼦句在执⾏时发⽣异常 ,就⼀定会进⼊某⼀个catch⼦句执⾏。
C.如果try⼦句中没有可能发⽣异常的语句 ,会产⽣编译错误。
D. catch ⼦句处理异常后 ,会重新执⾏与之对应的try⼦句。
正确答案:A
A选项:这是正确的。在C++中,一个try块后面可以跟随多个catch块,每个catch块处理不同类型的异常。当try块中的代码抛出异常时,程序会查找与抛出异常类型相匹配的catch块并执行它。
B选项:这是不准确的。如果try块中抛出的异常类型与任何catch块都不匹配,并且没有提供默认的catch(…)块来捕获所有类型的异常,那么程序会调用std::terminate
函数,通常会导致程序异常终止。因此,并不是所有异常都会被捕获。
C选项:这是不正确的。try块中是否包含可能抛出异常的语句并不会导致编译错误。即使try块中的代码看起来不会抛出异常,你仍然可以使用try-catch结构来编写更健壮的代码,以处理可能由外部因素(如操作系统、硬件故障等)引起的异常。
D选项:这是不正确的。一旦catch块执行完毕,程序会继续执行紧跟在最后一个catch块或try-catch结构之后的代码,而不是重新执行try子句。try子句中的代码只会在进入try-catch结构时执行一次。
14、执⾏以下C++语⾔程序后,输出结果是( )。
#include <iostream>
using namespace std;
int main(){
int fib[10];
fib[0] = 0;
fib[1] = 1;
for (int i = 2; i < 10; i++)
fib[i] = fib[i - 1] + fib[i - 2];
cout << fib[10] << endl;
return 0;
}
A. 0
B. 5
C. 55
D. ⽆法确定。
正确答案:D
这段C++程序试图计算斐波那契数列的前10个元素,但有一个关键错误。程序中的循环计算了fib[2]到fib[9]的值,但试图输出fib[10]的值,这并没有在循环中被初始化或赋值。
在C++中,未初始化的局部变量通常包含垃圾值,即它们可能包含任何值,这取决于它们在内存中的位置以及之前可能存储在那里的任何数据。因此,输出结果是无法确定的,所以正确答案是D。
15、在下列代码的横线处填写( ),完成对有 n个int类型元素的数组array 由⼩到⼤排序。
void BubbleSort(int array[], int n){
for (int i = n; i >= 2; i--)
for (_________) // 在此处填写代码
if (array[j] > array[j + 1]){
int t = array[j];
array[j] = array[j + 1];
array[j + 1] = t;
}
}
A. int j = 1; j < n; j++
B. int j = 0; j < n; j++
C. int j = 0; j < i - 1; j++
D. int j = 0; j < i; j++
正确答案:C
在冒泡排序中,外层循环控制排序的轮数,内层循环控制每一轮中相邻元素的比较和交换。因为外层循环变量i从n开始递减到2,表示我们总共要进行n-1轮排序。
在每一轮排序中,内层循环需要比较前i-1个元素,因为最后n-i个元素在上一轮或之前的轮次中已经排好序了。所以内层循环的起始索引是0,终止索引是i-1。
判断题(每题 2 分,共 20 分)
1、在C++语言中 ,指针变量在逻辑上指向另⼀个变量在内存中的位置,指针变量本身不占用内存。
正确答案:错误
指针变量本身确实占用内存。它存储的是它所指向的变量的内存地址。指针变量的大小取决于系统架构(例如,32位系统上的指针通常是4字节,64位系统上的指针通常是8字节)。
2、对N个元素的数组执⾏插⼊排序算法 ,通常的时间复杂度是 O ( N 2 ) O(N^2) O(N2)。
正确答案:正确
插入排序的基本操作是,对于数组中的每个元素,将其插入到已排序部分的正确位置。在最坏和平均情况下,插入排序的时间复杂度是 O ( N 2 ) O(N^2) O(N2),其中N是数组的元素数量。
3、在C++语⾔中 ,每个变量都有其作用域。
正确答案:正确
在C++中,变量的作用域决定了变量在程序中的可见性和生命周期。作用域可以是局部的(在函数或代码块内)、全局的(在整个程序中)。
4、在C++语⾔中 ,在函数调用时 ,通过引用传递的参数不会复制实际参数,因此不会额外占用内存。
正确答案:错误
在C++中,当使用引用(reference)传递参数时,确实不会复制实际参数的值,而是直接使用原始数据的内存地址。但是,这并不意味着不会“额外占用内存”。因为引用本身只是一个别名,它在内存中不直接占用空间,但引用的对象(即实际参数)在内存中是有存储空间的。
5、在C++语⾔中,可以通过定义结构体,定义⼀个新的数据类型。
正确答案:正确
在C++中,结构体(struct)是一种用户定义的数据类型,它允许你将多个不同类型的数据组合成一个单一的类型。通过定义结构体,你可以创建具有多个字段(或称为成员)的复合数据类型。
6、在C++语⾔中 ,可以定义结构体类型的数组变量 ,定义结构体时也可以包含数组成员。
正确答案:正确
在C++中,你可以定义结构体类型的数组变量,这意味着数组的每个元素都是一个结构体实例。同样,你也可以在结构体定义中包含其他类型的数组作为成员,包括字符数组(通常用于存储字符串)或其他结构体数组。
7、如果希望记录10个最长为99字节的字符串,可以将字符串数组定义为 char s[10][100]; 。
正确答案:正确
这个定义创建了一个二维字符数组,其中每一行(或称为元素)可以存储一个字符串。每个字符串的最大长度是99字节(加上一个空字符’\0’作为字符串的结束标记),所以每行分配了100个字符的空间。这样,你可以存储10个这样的字符串。
8、一个可能抛出异常的函数,调用它的位置没有在try⼦句中,会引起编译错误。
正确答案:错误
在C++中,即使一个函数可能抛出异常,你也可以在不在try块中直接调用它。这不会引起编译错误。然而,如果该函数确实抛出了异常,并且没有被任何catch块捕获,那么程序将调用terminate并终止执行。通常,我们推荐在可能抛出异常的函数调用周围使用try-catch块来处理或至少记录这些异常。
9、==和:=都是C++语⾔的运算符。
正确答案:错误
== 是C++中的等于运算符,用于比较两个值是否相等。但是,:= 不是C++的运算符。在C++中,赋值通常使用单个等号 =。:= 是某些其他编程语言(如Pascal和Go)中的赋值运算符,但在C++中不存在。
10、通过使用文件重定向操作,可以将程序中输出到cout的内容输出到文件中,这是常用的记录程序运⾏日志的方法之⼀。
正确答案:正确
正确:虽然C++标准库本身并不直接支持文件重定向操作(这是某些其他编程语言或环境的功能,如Unix shell),但你可以通过改变cout所关联的输出流来实现类似的效果。通常,这是通过将cout的流缓冲区与文件流关联起来完成的。这样,原本输出到cout的内容就会被重定向到文件中,从而实现了记录程序运行日志的目的。
#include <iostream>
#include <fstream>
using namespace std;
int main() {
ofstream logfile("logfile.txt");
streambuf* coutbuf = cout.rdbuf(); // 保存cout的原始缓冲区
cout.rdbuf(logfile.rdbuf()); // 将cout的输出重定向到logfile
cout << "This will be written to the logfile.\n";
cout.rdbuf(coutbuf); // 恢复cout的原始缓冲区
return 0;
}
编程题 (每题 25 分,共 50 分)
进制转换
【问题描述】
N进制数指的是逢N进⼀的计数制。例如,⼈们日常⽣活中⼤多使用⼗进制计数,而计算机底层则⼀般使用二进制。除此之外,⼋进制和⼗六进制在⼀些场合也是常⽤的计数制(⼗六进制中,⼀般使用字母A 至F表⽰⼗⾄⼗五;本题中,⼗⼀进制到⼗五进制也是类似的)。
在本题中,我们将给出 N个不同进制的数。你需要分别把它们转换成⼗进制数。
【提示】
对于任意⼀个L位K进制数,假设其最右边的数位为第 0位,最左边的数位为第 L - 1 位,我们只需要将其第i位的数码乘以权值 K
i,再将每位的结果相加,即可得到原K进制数对应的⼗进制数。下⾯是两个例⼦:
1.⼋进制数1362 对应的⼗进制数为
1
×
8
3
+
3
×
8
2
+
6
×
8
1
+
2
×
8
0
=
754
1 × 8^3+3 × 8^2+6 × 8^1+2 × 8^0= 754
1×83+3×82+6×81+2×80=754;
2.⼗六进制数3F0 对应的⼗进制数为
3
×
1
6
2
+
15
×
1
6
1
+
0
×
1
6
0
=
1008
3 × 16^2+15 × 16^1+ 0 × 16^0= 1008
3×162+15×161+0×160=1008 。
【输入描述】
输⼊的第⼀⾏为⼀个⼗进制表示的整数N。接下来N⾏,每⾏⼀个整数K,随后是⼀个空格,紧接着是⼀个K进制数,表示需要转换的数。保证所有K进制数均由数字和⼤写字母组成,且不以0开头 。保证K进制数合法。保证N ≤ 1000 ;保证2 ≤ K ≤ 16。
保证所有K进制数的位数不超过9。
【输出描述】
输出N行,每⼀个十进制数,表⽰对应K进制数的十进制数值。
【样例输入 1】
2
8 1362
16 3F0
【样例输出 1】
754
1008
【样例输入 2】
2
2 11011
10 123456789
【样例输出 2】
27
123456789
#include <iostream>
#include <string>
#include <cmath>
using namespace std;
/*char str_num[] = {'0', '1', '2', '3', '4',
'5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F'};
*/
string str_num = "0123456789ABCDEF";
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++){
long long k, ans = 0, wei = 0;
string num;
cin >> k >> num;
for (int j = num.length() - 1; j >= 0; j--){
int index = str_num.find(num[j], 0);
//cout << index << endl;
ans += index * pow(k, wei++);
}
cout << ans << endl;
}
return 0;
}
【题目大意】
1.有n个k进制的整数,将它们分别转换成对应的十进制。
【考纲知识点】
1.基本运算、输入输出语句、循环、进制转换的知识。
【解题思路】
1.按题目要求定义好需要的变量,并实现输入;
2.输入n行,每行2个整数,分别表示进制和要转换的数字;3.按求进制方法求即可。例如:
(
a
b
c
)
2
=
a
∗
2
2
+
b
∗
2
1
+
c
∗
2
0
(abc)_2=a*2^2+b*2^1+c*2^0
(abc)2=a∗22+b∗21+c∗20
#include <iostream>
#include <cstring>
using namespace std;
int trans_digit(int k, char c){
if (c <= '9')
return (c - '0');
return (c - 'A' + 10);
}
long long trans (int k, char str[]) {
int l = strlen(str);
long long res = 0, pw = 1;
for (int i = l - 1; i >= 0; i--){
res += pw * trans_digit(k, str[i]);
pw *= k;
}
return res;
}
int main(){
int n = 0;
cin >> n;
for (int t = 0; t < n; t++){
int k = 0;
char str[10];
cin >> k >> str;
cout << trans(k, str) << endl;
}
return 0;
}
变长编码
【问题描述】
小明刚刚学习了三种整数编码方式:原码、反码、补码,并了解到计算机存储整数通常使用补码。但他总是觉得生活中很少用到231-1这么大的数,生活中常用的0 ~ 100这种数也同样需要用4个字节的补码表示,太浪费了些。热爱学习的小明通过搜索,发现了一种正整数的变长编码方式。这种编码方式的规则如下:
1.对于给定的正整数,首先将其表达为二进制形式。例如,(0){10} =(0){2},(926){10}=(1110011110){2}。
2.将二进制数从低位到高位切分成每组7 bit,不足7bit的在高位用0填补。例如,(0){2}变为0000000的一组,(1110011110){2}变为0011110和0000111的两组。
3.由代表低位的组开始,为其加入最高位。如果这组是最后一组,则在最高位填上0,否则在最高位填上1。于是,0的变长编码为00000000一个字节,926的变长编码为10011110和00000111两个字节。
这种编码方式可以用更少的字节表达比较小的数,也可以用很多的字节表达非常大的数。例如,987654321012345678的二讲制为(0001101 1011010 01101101001011 1110100 0100110 1001000 0010110 1001110){2}于是它的变长编码为(十六进制表示) CE 96 C8 A6 F4 CB B6 DA OD,共9个字节。
你能通过编写程序,找到一个正整数的变长编码吗?
【输入描述】
输⼊第⼀⾏ ,包含⼀个正整数N。约定0≤N≤1018。
【输出描述】
输出⼀⾏ ,输出N对应的变长编码的每个字节 ,每个字节均以2位⼗六进制表示(其中, A-F使⽤⼤写字母表⽰) , 两个字节间以空格分隔。
【样例输入 1】
0
【样例输出 1】
00
【样例输入 2】
926
【样例输出 2】
9E 07
【样例输入 3】
987654321012345678
【样例输出 3】
CE 96 C8 A6 F4 CB B6 DA 0D
【题目大意】
1.给一个正整数,根据题目要求找它的变长编码,变长编码用16进制表示。
【考纲知识点】
1.基本运算、输入输出语句、一维数组、位运算的知识。【解题思路】
1.按题目要求定义好需要的变量,并实现输入;
2.根据题意,1、将n对应的二进制,每7位1组,保存起来;3.除了包含最高位那组,其他组最前面都增加1,例如中间一组是0001111,最前面加1变成10001111;
4.注意输出是先输出低位的数组,输出内容用16进制表示即可。
#include <iostream>
using namespace std;
/*
1. 将数据转换为二进制数
2. 将二进制数分成每组7bit, 低 ---> 高
3. 从低位组开始, 添加最高位,
如果是最后一组,高位添加0
不是最后一组,高位添加1
0001101 1011010 0110110 1001011 1110100 0100110 1001000 0010110 1001110
10:A 11:B 12:C 13:D 14:E 15:F
1001110 11001110 CE
0010110 10010110 96
1001000 11001000 C8
0100110 10100110 A6
1110100 11110100 F4
1001011 11001011 CB
0110110 10110110 B6
1011010 11011010 DA
0001101 00001101 13 ---> 0D
*/
string arr = "0123456789ABCDEF";
void print(int num){
cout << arr[num / 16] << arr[num % 16] << ' ';
}
int main() {
long long n;
cin >> n;
if (n == 0){
cout << "00\n";
return 0;
}
while (n > 0){
// 取出n中的低7位
int temp = (n & 0b01111111);
// 如果是低7位,则高位补1
if(n > 127){ // 111 1111
temp |= 0b10000000;
}else{ // 如果是高7位,则高位补0
temp |= 0b00000000;
}
n /= 128;// n缩小128倍
print(temp); // 输出这八位数转为十六进制数
}
return 0;
}