试卷 2023年CCF非专业级别软件能力认证第二轮 (CSP-S)提高级C++语言试题
2023年CCF非专业级别软件能力认证第二轮 (CSP-S)提高级C++语言试题
编程题
第 1 题    问答题

密码锁(lock)

【题目描述】

小Y有一把五个拨圈的密码锁。如图所示,每个拨圈上是从0到9的数字。每个拨圈都是从0到9的循环,即9拨动一个位置后可以变成0或8,

图1:密码锁

因为校园里比较安全,小Y采用的锁车方式是:从正确密码开始,随机转动密码锁仅一次;每次都是以某个幅度仅转动一个拨圈或者同时转动两个相邻的拨圈。当小Y选择同时转动两个相邻拨圈时,两个拨圈转动的幅度相同,即小Y可以将密码锁从00115转成11115,但不会转成12115。

时间久了,小Y也担心这么锁车的安全性,所以小Y记下了自己锁车后密码锁的n个状态,注意这n个状态都不是正确密码。

为了检验这么锁车的安全性,小Y有多少种可能的正确密码,使得每个正确密码都能够按照他所采用的锁车方式产生锁车后密码锁的全部n个状态。

【输入格式】

从文件lock.in中读入数据。

输入的第一行包含一个正整数n,表示锁车后密码锁的状态数。

接下来n行每行包含五个整数,表示一个密码锁的状态。

【输出格式】

输出到文件lock.out中。

输出一行包含一个整数,表示密码锁的这n个状态按照给定的锁车方式能对应多少种正确密码。


【样例1输入】

1
0 0 1 1 5

【样例1输出】

81

【样例1解释】

一共有81种可能的方案。

其中转动一个拨圈的方案有45种,转动两个拨圈的方案有36种。


【样例2】

见选手目录下的lock/lock2.in与lock/lock2.ans。

第 2 题    问答题

消消乐(game)

【题目描述】

小L现在在玩一个低配版本的消消乐,该版本的游戏是一维的,一次也只能消除两个相邻的元素。

现在,他有一个长度为n且仅由小写字母构成的字符串。我们称一个字符串是可消除的,当且仅当可以对这个字符串进行若干次操作,使之成为一个空字符串。

其中每次操作可以从字符串中删除两个相邻的相同字符,操作后剩余字符串会拼接在一起。

小L想知道,这个字符串的所有非空连续子串中,有多少个是可消除的。

【输入格式】

从文件game.in中读入数据。

输入的第一行包含一个正整数n,表示字符串的长度。

输入的第二行包含一个长度为n且仅由小写字母构成的的字符串,表示题目中询问的字符串。

【输出格式】

输出到文件game.out中。

输出一行包含一个整数,表示题目询问的答案。


【样例1输入】

8
accabccb

【样例1输出】

5

【样例1解释】

一共有5个可消除的连续子串,分别是cc、acca、cc、bccb、accabccb。


【样例2】

见选手目录下的game/game2.in与game/game2.ans。

【样例3】

见选手目录下的game/game3.in与game/game3.ans。

【样例4】

见选手目录下的game/game4.in与game/game4.ans。

第 3 题    问答题

结构体(struct)

【题目背景】

在C++等高级语言中,除了int和float等基本类型外,通常还可以自定义结构体类型。在本题当中,你需要模拟一种类似C++的高级语言的结构体定义方式,并计算出相应的内存占用等信息。

【题目描述】

在这种语言中,基本类型共有4种:byte,short,int,long,分别占据1,2,4,8字节的空间。

定义一个结构体类型时,需要给出类型名和成员,其中每个成员需要按顺序给出类.型和名称。类型可以为基本类型,也可以为先.定义过的结构体类型。注意,定义结构体类型时不会定义具体元素,即不占用内存。

定义一个元素时,需要给出元素的类型和名称。元素将按照以下规则占据内存:

• 元素内的所有成员将按照定义时给出的顺序在内存中排布,对于类型为结构体的成员同理。

• 为了保证内存访问的效率,元素的地址占用需要满足对齐规则,即任何类型的大小和该类型元素在内存中的起始地址均应对齐到该类型对齐要求的整数倍。具体而言:

–对于基本类型:对齐要求等于其占据空间大小,如int类型需要对齐到4字节,其余同理。

–对于结构体类型:对齐要求等于其成员的对齐要求的最大值,如一个含有int和short的结构体类型需要对齐到4字节。

以下是一个例子(以C++语言的格式书写):

struct d {
    short a;
    int b;
    short c;
};
d e;

该代码定义了结构体类型d与元素e。元素e包含三个成员e.a,e.b,e.c,分别占据第0∼1,4∼7,8∼9字节的地址。由于类型d需要对齐到4字节,因此e占据了第0∼11字节的地址,大小为12字节。

你需要处理n次操作,每次操作为以下四种之一:

1.定义一个结构体类型。具体而言,给定正整数k与字符串s,t1,n1,...,tk,nk,其中k表示该类型的成员数量,s表示该类型的类型名,t1,t2,...,tk按顺序分别表示每个成员的类型,n1,n2,...,nk按顺序分别表示每个成员的名称。你需要输出该结构体类型的大小和对齐要求,用一个空格分隔。

2.定义一个元素,具体而言,给定字符串t,n分别表示该元素的类型与名称。所有被定义的元素将按顺序,从内存地址为0开始依次排开,并需要满足地址对齐规则。你需要输出新定义的元素的起始地址。

3.访问某个元素。具体而言,给定字符串s,表示所访问的元素。与C++等语言相同,采用.来访问结构体类型的成员。如a.b.c,表示a是一个已定义的元素,它是一个结构体类型,有一个名称为b的成员,它也是一个结构体类型,有一个名称为c的成员。你需要输出如上被访问的最内层元素的起始地址。

4.访问某个内存地址。具体而言,给定非负整数addr,表示所访问的地址,你需要判断是否存在一个基本类型的元素占据了该地址。若是,则按操作3中的访问元素格式输出该元素;否则输出ERR。

【输入格式】

从文件struct.in中读入数据。

第1行:一个正整数n,表示操作的数量。

接下来若干行,依次描述每个操作,每行第一个正整数op表示操作类型:

•若op=1,首先输入一个字符串s与一个正整数k,表示类型名与成员数量,接下来k行每行输入两个字符串ti,ni,依次表示每个成员的类型与名称。

•若op=2,输入两个字符串t,n,表示该元素的类型与名称。

•若op=3,输入一个字符串s,表示所访问的元素。

•若op=4,输入一个非负整数addr,表示所访问的地址。

【输出格式】

输出到文件struct.out中。

输出n行,依次表示每个操作的输出结果,输出要求如题目描述中所述。


【样例1输入】

5
1 a 2
short aa
int ab
1 b 2
a ba
long bb
2 b x
3 x.ba.ab
4 10

【样例1输出】

8 4
16 8
0
4
x.bb

【样例1解释】

结构体类型a中,int类型的成员aa占据第0∼3字节地址,short类型的成员ab占据第4∼5字节地址。又由于其对齐要求为4字节,可得其大小为8字节。由此可同理计算出结构体类型b的大小为16字节,对齐要求为8字节。

【样例2】

见选手目录下的struct/struct2.in与struct/struct2.ans。

【样例2解释】

第二个操作4中,访问的内存地址恰好在为了地址对齐而留下的“洞”里,因此没有基本类型元素占据它。

【样例3】

见选手目录下的struct/struct3.in与struct/struct3.ans。

【数据范围】

对于全部数据,满足1≤n≤100,1≤k≤100,0≤addr≤1018。

所有定义的结构体类型名、成员名称和定义的元素名称均由不超过10个字符的小

写字母组成,且都不是byte,short,int,long(即不与基本类型重名)。

所有定义的结构体类型名和元素名称互不相同,同一结构体内成员名称互不相同。

但不同的结构体可能有相同的成员名称,某结构体内的成员名称也可能与定义的结构体或元素名称相同。

保证所有操作均符合题目所述的规范和要求,即结构体的定义不会包含不存在的类型、不会访问不存在的元素或成员等。

保证任意结构体大小及定义的元素占据的最高内存地址均不超过1018

特殊性质A:没有操作1;

特殊性质B:只有一个操作1;

特殊性质C:所有操作1中给出的成员类型均为基本类型;

特殊性质D:基本类型只有long。

【提示】

对于结构体类型的对齐要求和大小,形式化的定义方式如下:

•设该结构体内有k个成员,其大小分别为s1,...,sk,对齐要求分别为a1,...,ak

•则该结构体的对齐要求为a=max{a1,...,ak};

•再设这些成员排布时的地址偏移量分别为o1,...,ok,则:

–o1=0;

–对于i=2,...,k,oi为满足oi−1+si−1≤oi且ai整除oi的最小值;

–则该结构体的大小s为满足ok+sk≤s且a整除s的最小值;

对于定义元素时的内存排布,形式化的定义方式如下:

•设第i个被定义的元素大小为si,对齐要求为ai,起始地址为bi

•则b1=0,对于2≤i,bi为满足bi−1+si−1≤bi且ai整除bi的最小值。

第 4 题    问答题

种树(tree)

【题目描述】

你是一个森林养护员,有一天,你接到了一个任务:在一片森林内的地块上种树,并养护至树木长到指定的高度。

森林的地图有n片地块,其中1号地块连接森林的入口。共有n−1条道路连接这些地块,使得每片地块都能通过道路互相到达。最开始,每片地块上都没有树木。

你的目标是:在每片地块上均种植一棵树木,并使得i号地块上的树的高度生长到不低于ai米。

你每天可以选择一个未种树且与某个已种树的地块直接邻接(即通过单条道路相.连)的地块,种一棵高度为0米的树。如果所有地块均已种过树,则你当天不进行任何操作。特别地,第1天你只能在1号空地种树。

对每个地块而言,从该地块被种下树的当天开始,该地块上的树每天都会生长一定的高度。由于气候和土壤条件不同,在第x天,i号地块上的树会长高max(bi+x∗ci,1)

米。注意这里的x是从整个任务的第一天,而非种下这棵树的第一天开始计算。

你想知道:最少需要多少天能够完成你的任务?

【输入格式】

从文件tree.in中读入数据。

输入的第一行包含一个正整数n,表示森林的地块数量。

接下来n行:每行包含三个整数ai,bi,ci,分别描述一片地块,含义如题目描述中所述。

接下来n−1行:每行包含两个正整数ui,vi,表示一条连接地块ui和vi的道路。

【输出格式】

输出到文件tree.out中。

输出一行仅包含一个正整数,表示完成任务所需的最少天数。


【样例1输入】

4
12 1 1
2 4 ‐1
10 3 0
7 10 ‐2
1 2
1 3
3 4

【样例1输出】

1 5

【样例1解释】

第1天:在地块1种树,地块1的树木长高至2米。

第2天:在地块3种树,地块1,3的树木分别长高至5,3米。

第3天:在地块4种树,地块1,3,4的树木分别长高至9,6,4米。

第4天:在地块2种树,地块1,2,3,4的树木分别长高至14,1,9,6米。

第5天:地块1,2,3,4的树木分别长高至20,2,12,7米。

【样例2】

见选手目录下的tree/tree2.in与tree/tree2.ans。

【样例3】

见选手目录下的tree/tree3.in与tree/tree3.ans。

【样例4】

见选手目录下的tree/tree4.in与tree/tree4.ans。


【数据范围】

对于所有测试数据有:1≤n≤105,1≤ai≤1018,1≤bi≤109,0≤|ci|≤109,1≤ui,vi≤n。保证存在方案能在109天内完成任务

特殊性质A:对于所有1≤i≤n,均有ci=0;

特殊性质B:对于所有1≤i<n,均有ui=i,vi=i+1;

特殊性质C:与任何地块直接相连的道路均不超过2条;

特殊性质D:对于所有1≤i<n,均有ui=1。

答题卡
编程题
1 2 3 4
题目总数:4
总分数:100
时间:不限时
QQ
公众号
客服
扫一扫