NOIP2013-普及组初赛C语言解析

第十九届全国青少年信息学奥林匹克联赛初赛

一、单项选择题(共 20 题,每题 1.5 分,共计 30 分。每题有且仅有一个正确选项)
1. 一个 32 位整型变量占用(A )个字节。
A. 4 B. 8 C. 32 D. 128

参考:一个int变量占4个字节,对于16字机,short int 占2个字节,在大多数的32位机中,short int 占4个字节。但总的来说,short int 至少16位,也就是2个字节,long int或long ,在内存中占4个字节。故选A

/============================================================================================/
2. 二进制数 11.01 在十进制下是( A) 。
A. 3.25 B. 4.125 C. 6.25 D. 11.125

参考:关于小数的二进制转十进制,先把整数按照一般方法转成二进制,小数部分,

举例:


所以本题中的整数二进制转换过程为:1*2º+1*2¹(从后往前乘)=3,
小数部分转换过程为:
0*2º+0*2^-1+1*2^-2=0.25
所以(11.01)₂=(3+0.25=3.25)
₀,故选A

/============================================================================================/
3. 下面的故事与( B)算法有着异曲同工之妙。
从前有座山,山里有座庙,庙里有个老和尚在给小和尚讲故事:‚从前有座山,山
里有座庙,庙里有个老和尚在给小和尚讲故事:‘从前有座山,山里有座庙,庙里有个
老和尚给小和尚讲故事....’‛
A. 枚举 B. 递归 C. 贪心 D. 分治

参考:这题一个套一个,无限循环,很明显是递归,故选B

/============================================================================================/
4. 逻辑表达式( C)的值与变量 A 的真假无关。
A. (A ˅ B) ˄ ¬A              B. (A ˅ B) ˄ ¬B
C. (A ˄ B) ˅ (¬A ˄ B)      D. (A ˅ B) ˄ ¬A ˄ B

参考:其中"∨" 表示"或" (逻辑加法),"∧" 表示"与". (逻辑乘法),"┐"表示"非". (逻辑否定),代入几组数据,可以求得“(A ˄ B) ˅ (¬A ˄ B)”的真假与A无关,故选C

/============================================================================================/
5. 将( 2, 6, 10, 17) 分别存储到某个地址区间为 0~10 的哈希表中, 如果哈希函数 h(x) =
D ),将不会产生冲突,其中 a mod b 表示 a 除以 b 的余数。
A. x mod 11 B. x2 mod 11
C. 2x mod 11 D. ⌊√ ⌋ mod 11,其中⌊√ ⌋表示√ 下取整

参考:所谓哈希表,就是建立一个数组模样的,通过对元素的某种计算出下表的位置放入,更加快捷(它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度),当0~10之内的数,mod 11向下取整就不会发生重复,故选D

/============================================================================================/
6. 在十六进制表示法中,字母 A 相当于十进制中的(B ) 。
A. 9 B. 10 C. 15 D. 16

参考:十六进制表:0,1,2,3,4,5,6,7,8,9,A(10),B(11),C(12),D(13),E(14),F(15),故选B

/============================================================================================/

7. 下图中所使用的数据结构是( B) 。

A. 哈希表 B. 栈 C. 队列 D. 二叉树

参考:只有一个出口,要想把底下的东西拿出来,只能把上面的东西先拿走,所以是栈,故选B

/============================================================================================/
8. 在 Windows 资源管理器中, 用鼠标右键单击一个文件时,会出现一个名为“复制”的

操作选项,它的意思是(C )。
A. 用剪切板中的文件替换该文件
B. 在该文件所在文件夹中,将该文件克隆一份
C. 将该文件复制到剪切板,并保留原文件
D. 将该文件复制到剪切板,并删除原文件

参考:Window系统中,“复制”是把文件放入剪切板,保留文件,点击“粘贴”时,从剪切板内发送到目标文件下,故选C

/============================================================================================/
9. 已知一棵二叉树有 10 个节点,则其中至多有(A )个节点有 2 个子节点。
A. 4 B. 5 C. 6 D. 7

参考:2³=8<x<2⁴=16,故选A

/============================================================================================/
10. 在一个无向图中,如果任意两点之间都存在路径相连,则称其为连通图。下图是一个有
4 个顶点、 6 条边的连通图。若要使它不再是连通图, 至少要删去其中的(C )条边。
A. 1 B. 2 C. 3 D. 4

参考:这是一个无向图,每个点都能到达其他任意一个点,则要使它不是连通图,则需要把一个点孤立在外,就需要删除3条边即可,故选C

/============================================================================================/
11. 二叉树的(A ) 第一个访问的节点是根节点。
A. 先序遍历 B. 中序遍历 C. 后序遍历 D. 以上都是

参考:先序遍历:先访问根节点,再到左右节点

        中序遍历:先访问左节点,再访问根节点,最后访问右节点

        后序遍历:先访问左节点,再到右节点,最后根节点

/============================================================================================/
12. A0作为起点,对下面的无向图进行深度优先遍历时,遍历顺序不可能是( ) 。
A. A0, A1, A2, A3 B. A0, A1, A3, A2 C. A0, A2, A1, A3 D. A0, A3, A1, A2

 参考:既然是深度优先遍历,就要一直访问到一个节点最后一层,则A是错的,A为广搜,故选A

/============================================================================================/

13. IPv4 协议使用 32 位地址,随着其不断被分配,地址资源日趋枯竭。因此,它正逐渐被
使用( D)位地址的 IPv6 协议所取代。
A. 40 B. 48 C. 64 D. 128

参考:IPv4地址就是四位IP地址,如:192.168.0.1,但随着社会的发展,IPv4地址很快被用尽,现在已经使用了128位的IPv6地址,如:00-01-00-01-1D-8F-D3-2A-90-E6-BA-E2-42-E3,故选D

/============================================================================================/
14. A )的平均时间复杂度为 O(n log n),其中 n 是待排序的元素个数。
A. 快速排序 B. 插入排序 C. 冒泡排序 D. 基数排序

参考:快速排序最好情况是n log n,最坏是n²,所以平均复杂度是n log n

/============================================================================================/
15. 下面是根据欧几里得算法编写的函数,它所计算的是 a b 的(C )。
int euclid(int a, int b)
{
if (b == 0)
return a;
else
return euclid(b, a % b);
}
A. 最大公共质因子 B. 最小公共质因子
C. 最大公约数 D. 最小公倍数

参考:从代码可以看出,是运用了函数递归,辗转相除法求最大公约数,故选C

/============================================================================================/
16. 通常在搜索引擎中,对某个关键词加上双引号表示(C ) 。
A. 排除关键词,不显示任何包含该关键词的结果
B. 将关键词分解,在搜索结果中必须包含其中的一部分
C. 精确搜索,只显示包含整个关键词的结果
D. 站内搜索,只显示关键词所指向网站的内容

参考:这题是常识题,例如在百度中,在内容前后加上双引号表示的是精确搜索(词条不会被分开),故选C

/============================================================================================/
17. 中国的国家顶级域名是( A)。
A. .cn B. .ch C. .chn D. .china

参考:这题是常识题,A是中国国家顶级域名,B是瑞士的域名,C选项chn虽然是中国的意思,但没有这个域名,D选项更不可能,故选A

/============================================================================================/
18. 把 64 位非零浮点数强制转换成 32 位浮点数后, 不可能( D)。
A. 大于原数 B. 小于原数
C. 等于原数 D. 与原数符号相反

参考:把一个 64 位非零浮点数强制转换成 32 位浮点数后,符号不可能相反,只是数可能变大变小或者不变,故选D

/============================================================================================/
19. 下列程序中,正确计算 1, 2, …, 100 这 100 个自然数之和 sum (初始值为 0)的是(A

 

参考:i初值为1,sum每次+i,且while循环(i≤100成立)加上,A正确,B只有当i>100时成立,错误,C还要考虑等于100的情况,错误,D的错误和B一样,故选A

/============================================================================================/

20. CCF NOIP 复赛全国统一评测时使用的系统软件是(B )。
A. NOI Windows B. NOI Linux C. NOI Mac OS D. NOI DOS

参考:目前NOIP复赛用的是虚拟机评测,用的是Linux系统,故选B
/============================================================================================/

二、问题求解(共 2 题,每题 5 分,共计 10 分;每题全部答对得 5 分, 没有部分分)

1.7个同学围坐一圈,要选两个不相邻的人作为代表,有  14  种不同的选法

参考:可以把这七个人想象成为一个七边形,问题变为了“求七边形有多少条对角线”,这样就可以运用公式求出共有x个选法(x条对角线)=n(n-3)/2=14

/===========================================================================================/

2.某程序自称使用了一种防窃听的方式验证用户密码。密码是n个数S₁、S₂…Sn,均为0或1.该系统随机生成n个数,a,a…an,均为0或1,请用户回答(Sa+Sa+…Snan)除以二的余数。如果多次回答总是正确,即认为掌握密码。该系统认为,及时回答的过程被泄露,也无助于破解密码——因为用户并没有直接发送密码。

然而,事与愿违。例如,当n=4时,有人窃听了以下五次回答:

就破解出了密码S₁=  0  S₂=  1  S=  1  S₄=  1  

参考:根据用户的回答,代入a1、a2、a3、a4,可以倒推出有关S1,S2,S3,S4的关系式:

(S1+S2)%2=1①    (S1+S2+S3)%2=0④

(S3+S4)%2=0②    (S1)%2=0⑤

(S2+S3)%2=0③

根据上面五个式子中的⑤式,可以推出S1=0,将S1代入①式,得出S2=1,将S2代入③式,得出S3=1,将S3代入②式,得出S4=1;

三、阅读程序写结果(共 4 题,每题 8 分,共计 32

 1.

1 #include <stdio.h>
2 int main()
3 {
4     int a,b;
5     scanf("%d%d",&a,&b);
6     printf("%d+%d=%d\n",a,b,a+b);
7     return 0;
8 }

输入:3 5

输出:     3+5=8       

参考:这题简单,输入两个数a,b,写出表达式"a+b=c",所以是3+5=8

/============================================================================================/

 2.

 1 #include <stdio.h>
 2 int main() 
 3 {
 4    int a,b,u,i,num;
 5    scanf("%d%d%d",&a,&b,&u);
 6    num=0;
 7    for(i=a;i<=b;i++) 
 8    {
 9       if((i%u)==0)
10       num++;
11    }
12    printf("%d\n",num);
13    return 0;
14 }

输入:1 100 15

输出:      6           

参考:这题简单,从代码中不难看出,从a-b这个范围内寻找u的倍数有多少个,所以是6

/============================================================================================/

3.

 

 1 #include <stdio.h>
 2 const int SIZE=100;
 3 int main() 
 4 {
 5    int n,f,i,left,right,middle,a[SIZE];
 6    scanf("%d%d",&n,&f);//输入两个数n和f
 7    for(i=1;i<=n;i++)//循环n次
 8    scanf("%d",&a[i]);//每次输入一个数存入数组a
 9    left=1;//left标记为第一
10    right=n;//right标记为最后
11    do
12    {
13       middle=(left+right)/2;//middle赋值为左右中值
14       if(f<=a[middle]){//如果f小于a数组中间那个数      
15           right=middle;//right标记为中值 
16       }
17       else{
18           left=middle+1;//否则left标记为中值+1 
19       }   
20    }while(left<right);//循环直到left≥right时结束
21    printf("%d\n",right);//输出f在数组a中的位置 
22    return 0;
23 }

输入:12 17

      2 4 6 9 11 15 17 18 19 20 21 25

输出:      7      

参考:从代码可以看出,输入两个数n和f,循环n次,每次输入一个数存入数组a。定义两个数left、right分别标记为第一和最后。在下面一个while循环直到left≥right时结束。这个循环中,middle赋值为左右中值,如果f小于a数组中间那个数right标记为中值,反之left标记为中值+1,重复过程,从这个过程可以看出,左和右每次都折半,寻找f(二分查找f在数组a中的位置),最后输出f的位置。所以17在"2 4 6 9 11 15 17 18 19 20 21 25"中的位置是第7个。

二分查找这种算法是比较高效的,在编程中经常要用到。

/============================================================================================/

4.

 1 #include <stdio.h>
 2 const int SIZE=100;//宏定义SIZE代表100 
 3 int main()
 4 {
 5    int height[SIZE],num[SIZE],n,ans;//height数组表示高度,num表示升序列长度 
 6    int i,j;
 7    scanf("%d",&n);//输入共有n个数 
 8    for(i=0;i<n;i++)
 9    {
10       scanf("%d",&height[i]);//每次输入一个数到数组height中 
11       num[i]=1;//长度标记为1 
12       for(j=0;j<i;j++)//从0~i范围内寻找能和i构成最长升序序列的数 
13         {
14          if((height[j]<height[i])&&(num[j]>=num[i]))//如果i比前面的一个数大,且num长度最大(0~i能和i构成目前最长升序子序列) 
15          num[i]=num[j]+1;//则升序子序列长度+1 
16       }
17    }
18    ans=0;//ans清零 
19    for(i=0;i<n;i++)//寻找num数组中的最大升序列长度ans,输出 
20    {
21       if(num[i]>ans) ans=num[i];//发现有一个更长的长度,ans标记为当前 
22    }
23    printf("%d\n",ans);
24    return 0;
25 }

输入:6

        2 5 3 11 12 4

输出:        4        

参考:这题较为复杂,题目中要求输入一组高度,每次从0~i寻找之前的数是否小于当前i并且长度num要大于i当前的num值,满足条件,加上去。如果不明白意思的话,可以模拟一下过程即可

所以这个代码的作用是:求一个数列中最大升序子序列长度,所以题目中的"2 5 3 11 12 4"中最大升序子序列是“2 3 11 12”,长度是4。

/============================================================================================/

四、完善程序( 共 2 题, 每题 14 分, 共计 28 分)

1.( 序列重排) 全局数组变量 a 定义如下:
它记录着一个长度为 n 的序列 a[1], a[2], …, a[n]。
现在需要一个函数, 以整数 p (1 ≤ p n)为参数,实现如下功能: 将序列 a 的前 p
个数与后 n p 个数对调, 且不改变这 p 个数(或 n p 个数)之间的相对位置。例如,
长度为 5 的序列 1, 2, 3, 4, 5,当 p = 2 时重排结果为 3, 4, 5, 1, 2。
有一种朴素的算法可以实现这一需求, 其时间复杂度为 O(n)、空间复杂度为 O(n):

 

参考:这题呢,较为简单,我们先开第一段代码。这段代码较为朴素,第一个for循环是把p后面的数存入b数组,

posted @ 2015-09-19 21:58  Memoryヾノ战心  阅读(3706)  评论(0编辑  收藏  举报