NOIP 2017初賽普及組C/C++答案詳解

海天一樹發表於2018-04-26

競賽時間: 2017 年 10月14日 14:30~ 16:30
選手注意:不得使用任何電子裝置(如計算器、手機、電子詞典等 )或查閱任何書籍資料

一、單項選擇題(共20題,每題1.5分,共計30分;每題有且僅有一個正確選項)

1.在8位二進位制補碼中,10101011表示的數是十進位制下的( )
A. 43 B. -85 C. -43 D. -84

2.計算機儲存資料的基本單位是( )
A. bit B. Byte C. GB D. KB

3.下列協議中與電子郵件無關的是( )
A. POP3 B. SMTP C WTO D IMAP

4.解析度為800*600、16位色的點陣圖,儲存影像資訊所需的空間為( )
A. 937.5KB B. 4218.75KB C. 4320KB D. 2880KB

5.計算機應用的最早領域是( )
A. 數值計算 B. 人工智慧 C. 機器人 D. 過程控制

6.下列不屬於物件導向程式設計語言的是( )
A. C B. C++ C. Java D. C#

7.NOI的中文意思是( )
A. 中國資訊學聯賽 B. 全國青少年資訊學奧林匹克競賽
C. 中國青少年資訊學奧林匹克競賽 D. 中國計算機學會

8.2017年10月1日是星期日,1999年10月1日是( )
A. 星期三 B.星期日 C. 星期五 D.星期二

9.甲、乙、丙三位同學選修課程,從4門課程中,甲選修2門,乙、丙各選修3門,則不同的選修方案共有( )
A. 36 B. 48 C. 96 D. 192

10.設G是有n個結點、m條邊(n≤m)的連線圖,必須刪去G的( )條邊,才能使得G變成一棵樹。
A. m-n+1 B. m-n C. m+n+1 D. n-m+1

11.對於給定的序列{ak},我們把(i , j)稱為逆序對當且僅當 i<j且ai > aj .那麼序列1,7,2,3,5,4的逆序對數為( )個
A. 4 B. 5 C. 6 D. 7

12.表示式a*(b+c)*d的字尾形式是( )
A. abcd*+*
B. abc+*d*
C. a*bc+*d
D. b+c*a*d

13.向一個棧頂指標為hs的鏈式棧中插入一個指標s指向的結點時,應執行( )
A. hs->next =s ;
B. s->next=hs; hs=s ;
C. s->next=hs->next;hs->next=s;
D. s->next=hs; hs=hs->next;

14.若串S=“copyright”,其子串的個數是( )
A. 72 B. 45 C. 46 D. 36

15.十進位制小數13.375對應的二進位制數是( )
A. 1101.011 B. 10111.011 C. 1101.101 D. 1010.01

16.對於入棧順序為a,b,c,d,e,f,g的序列,下列( )不可能是合法的出棧序列
A. a,b,c,d,e,f,g B. a,d,c,b,e,g,f C. a,d,b,c,g,f,e D. g,f,e,d,c,b,a

17.設A和B是兩個長為n的有序陣列,現在需要將A和B合併成一個排好序的陣列,任何以元素比較作為基本運算的歸併演算法在最壞情況下至少要做( )次比較
A. n2 B. n log n C. 2n D. 2n-1

18.從( )年開始,NOIP競賽將不再支援Pascal語言
A. 2020 B. 2021 C. 2022 D. 2023

19.一家四口人,至少兩個人生日屬於同一月份的概率是( )
(假定每個人生日屬於每個月份的概率相同且不同人之間相互獨立)
A. 1/12 B. 1/144 C. 41/96 D. 3/4

20.以下和計算機領域密切相關的獎項是( )
A. 奧斯卡獎 B. 圖靈獎 C. 諾貝爾獎 D. 普利策獎

二、問題求解(共2題,每題5分,共計10分)

1.一個人站在座標(0,0)處,面朝x軸正方向。第一輪,他向前走1單位距離,然後右轉;第二輪,他向前走2單位距離,然後右轉;第三輪,他向前走3單位 距離,然後右轉……他一直這麼走下去。請問第2017輪後,他的座標是:(,_)。(請在答題紙上用逗號隔開兩空答案)

2-1.png

2.如下圖所示,共有13個格子。對任何一個格子進行一次操作,會使得它自己以及與它上下左右相鄰的格子中的數字改變(由1變0,或由0變1)。現在要使得所有的格子中的數字都變為0,至少需要_____次操作。

2-2.png

三、閱讀程式寫結果(共4題,每題8分,共計32分)

#include <stdio.h>
#include <string.h>

int main()
{
    int t[256];
    char s[10];
    int i;
    scanf("%s", s);

    for(i = 0; i < 256; i++)
        t[i] = 0;

    for(i = 0; i < strlen(s); i++)
        t[s[i]]++;

    for(i = 0; i < strlen(s); i++)
        if(t[s[i]] == 1)
        {
            printf("%c\n", s[i]);
            return 0;
        }

    printf("no\n");

    return 0;
}

輸入: xyzxyw
輸出:___________.

#include <stdio.h>

int g(int m, int n, int x)
{
    int ans=0;
    int i;

    if(n == 1)
        return 1;

    for(i = x; i <= m / n; i++)
        ans += g(m - i, n - 1, i);

    return ans;
}

int main()
{
    int t, m, n;
    scanf("%d%d", &m, &n);
    printf("%d\n", g(m, n, 0));

    return  0;
}

輸入: 7 3
輸出:__________.

#include <stdio.h>
#include <string.h>

int main()
{
    char ch[200];
    int a[200];
    int b[200];
    int n, i, t, res;

    scanf("%s", ch);
    n = strlen(ch);
    for(i = 0; i < 200; i++)
        b[i] = 0;

    for(i = 1; i <= n ; i++)
    {
        a[i] = ch[i-1] - '0';
        b[i] = b[i-1] + a[i];
    }

    res = b[n];
    t = 0;

    for(i = n; i > 0; i--)
    {
        if(a[i] == 0)
            t++;

        if(b[i-1] + t < res)
            res = b[i-1] + t;
    }

    printf("%d\n", res);

    return 0;
}

輸入: 1001101011001101101011110001
輸出:____________________________.

#include <stdio.h>

int main()
{
    int n, m;
    scanf("%d%d", &n, &m);

    int x = 1;
    int y = 1;
    int dx = 1;
    int dy = 1;
    int cnt = 0;
    int myCnt = 0;

    while(cnt != 2)
    {
        myCnt++;
        cnt = 0;
        x = x + dx;
        y = y + dy;

        if(x == 1 || x == n)
        {
            ++cnt;
            dx = -dx;
        }

        if(y == 1 || y == m)
        {
            ++cnt;
            dy = -dy;
        }
    }

    printf("%d %d\n", x, y);

    return  0 ;
}

輸入1: 4 3
輸出1: _________________(3分)

輸入2:2017 1014
輸出 2: ________________ (5分)

四、完善程式 (共2題,每題14分,共計28分)

1.(快速冪)請完善下面的程式,該程式使用分治法求 x^p mod m的值。(第一空2分,其餘3分)
輸入:三個不超過 10000的正整數 x, p, m .
輸出:x^p mod m的值。
提示:若p為偶數,x^p = (x^2)^p/2; 若p為奇數,x^p = x * (x^2)^(p-1)/2

#include  <stdio.h>
int x, p, m, i, result;

int main()  
{
    scanf("%d%d%d", &x, &p, &m) ;
    result = __(1)_____;
    
    while( __(2)______)  
    {
        if(p % 2 == 1)
            result = __(3)_______;
        p /= 2;
        x = __(4)_______;
    }
    
    printf("%d\n", __(5)_____);
    
    return  0 ;
}

2.(切割繩子) 有n條繩子,每條繩子的長度已知且均為正整數。繩子可以以任意正整數長度切割,但不可以連線。現在要從這些繩子中切割出m條長度相同的繩段,求繩段的最大長度是多少。(第一、二空2.5分,其餘3分)
輸入:第一行是一個不超過100的正整數n,第二行是n個不超過10 ^ 6的正整數,表示每條繩子的長度,第三行是一個不超過10 ^ 8的正整數m。
輸出 :繩段的最大長度,若無法切割,輸出Failed.

#include  <stdio.h>

int n, m, i, lbound, ubound, mid, count;
int  len[100];  //繩子長度
   
int main()  
{
    scanf("%d", &n) ;
    count = 0;
    
    for(i = 0; i < n; i++) 
    {
         scanf("%d", &len[i]);
         ____(1)________;
    }
    
    scanf("%d", &m);
    
    if( ___(2)_____)  
    {
        printf("Failed\n") ;
        return  0 ;
    }
    
    lbound =1 ;
    ubound =1000000 ;
    while ( ____(3)______ )  
    {
        mid = ___(4)______;
        count =0 ;
    
        for(i = 0; i < n; i++ )
            ___(5)_____ ;
            
        if(count < m) 
          ubound = mid – 1 ;
        else 
          lbound = mid ;
    }
       
    printf("%d\n", lbound);
    
    return 0;
} 

參考答案

一、單項選擇題

1 B
原碼、反碼、補碼請參考 https://www.jianshu.com/p/b53fe5765884
正數的原碼與反碼、補碼相同。
負數的反碼為原碼取反,最高位符號位不變;負數的補碼為原碼取反加1,最高位符號位不變。

所以,負數的原碼為補碼減1取反,最高位為符號位不用變。
10101011減1變成10101010,再取反變成11010101
11010101 = -(64 + 16 + 4 + 1) = -85

2 B

3 C
POP3: Post Office Protocol - Version 3,郵局協議3
SMTP: Simple Mail Transfer Protocol,簡單郵件傳輸協議
WTO: World Trade Organization,世界貿易組織
IMAP: Internet Mail Access Protocol,因特網郵件訪問協議

4 A
8 bit = 1 B
1024 B = 1KB
800 * 600 * 16 / (8 * 1024) = 937.5kB

5 A
美國最早用於計算彈道和射擊路線,即數值分析

6 A
C語言是程式導向的語言

7 B
NOI: National Olypiad in Infomatics,全國青少年資訊學奧林匹克競賽
NOIP: National Olypiad in Infomatics in Provices,全國青少年資訊學奧林匹克聯賽

8 C
非閏年,X年10月1日到X+1年10月1日,經過365天。365 % 7 = 1,在星期上相當於過了一天。
閏年一年366天,366 % 7 = 2,在星期上相當於過了二天。
判斷閏年有兩個條件:能被400整除;或能被4整除且不能被100整除。
1999年10月1日~2017年10月1日,這18年裡有13個非閏年5個閏年(2000,2004,2008,2012,2016),相當於經過13 + 5 * 2 = 23天,23 % 7 = 2,相當於經過了2天。
星期日 - 2 = 星期五。

9 C
求組合數:C(4, 2) * C(4, 3) * C(4, 3) = 6 * 4 * 4 = 96

10 A

a-1.jpg

樹的節點數 = 邊數 + 1,比如上圖中節點10個,邊有9條。
題目中,圖要變成樹,只能保留n - 1條邊。m - (n - 1) = m - n + 1

11 B
7 2, 7 3, 7 5, 7 4, 5 4。共五對。

12 B
考察利用棧將中綴表示式變為字尾表示式。可參考《大話資料結構》4.9–棧的應用。
中綴表示式轉換成字尾表示式的規則:
(1)遇到運算元:直接輸出(新增到字尾表示式中)
(2)棧為空時,遇到運算子,直接入棧
(3)遇到左括號:將其入棧
(4)遇到右括號:執行出棧操作,並將出棧的元素輸出,直到彈出棧的是左括號,左括號不輸出
(5)遇到其他運算子:加減乘除:彈出所有優先順序大於或者等於該運算子的棧頂元素,然後將該運算子入棧
(6)最終將棧中的元素依次出棧,輸出

本題中的執行順序為:
(1)輸出a,
(2)“”、“(”依次入棧
(3)輸出b
(4)“+”入棧
(5)輸出c
(6)遇到右括號,將棧頂元素“+”出棧並輸出,將棧頂元素“(”出棧但不用輸出
(7)遇到“
”,因為棧中只有一個元素“”,運算子相等,所以“”出棧並輸出,新遇到的“”入棧
(8)輸出d
(9)將棧中的元素“
”輸出
所以,輸出的順序,即字尾形式為“abc+d

13 B
考察棧的資料結構,可參考 https://www.jianshu.com/p/f9e4961bf145
新元素入棧後,要把棧頂指標指到新元素的位置。

14 C
長度為9的子串有9-9+1=1個,即S本身。
長度為8的子串有9-8+1=2個,即"copyrigh"和"opyright"。
長度為7的子串有9-7+1=3個,即"copyrig", “opyrigh"和"pyright”
……
長度為1的子串有9-1+1=9個,即"c", “o”, “p”, “y”, “r”, “i”, “g”, “h”, “t”
長度為0的子串有1個,即空串""

公式cnt = len * (len + 1) / 2 + 1

15 A
整數部分,1101 = 2^3 + 2^2 + 2^0 = 13,排除BD
小數部分,小數十進位制轉二進位制,就是小數部分不斷乘以2直到小數完全消失,計算過程中每次取整數部分作為二進位制值。
0.375 * 2 = 0.75 ,取整數部分0
0.75 * 2 = 1.5,取整數部分1,其小數部分0.5參與下次計算
0.5 * 2 = 1,取整數部分1
所以小數部分為011

16 C
A中,每次進棧一個字母,然後該字母立馬出棧
B中,先入棧a,彈出a;再入棧bcd,彈出dcb;第三次入棧e,彈出e;最後入棧fg,彈出gf
C中,無論怎樣入棧,都不會有db的出棧順序
D中,把所有字母進棧,再把所有字母出棧

17 D
考察歸併排序,可參考《大話資料結構》9.8節。
這題考的是比較次數,而不是時間複雜度或空間複雜度。

先看看最好的情況,設有序陣列A[4] = {1, 3, 5, 7}, 有序陣列B[4] = {8, 10, 12, 14}, 陣列C[8]用來儲存比較後的結果。
1與8比較,把1放到C中,C[] = {1}
3與8比較,把3放到C中,C[] = {1, 3}
5與8比較,把5放到C中,C[] = {1, 3, 5}
7與8比較,把7放到C中,C[] = {1, 3, 5, 7}
剩下的不用比較,直接放到C中,C[] = {1, 3, 5, 7, 8, 10, 12, 14}
共比較了4次,即n次

再看看最壞的情況,設有序陣列A[4] = {1, 3, 5, 7}, 有序陣列B[4] = {2, 4, 6, 8}, 陣列C[8]用來儲存比較後的結果。
1與2比較,把1放到C中,C[] = {1}
2與3比較,把2放到C中,C[] = {1, 2}
3與4比較,把3放到C中,C[] = {1, 2, 3}
4與5比較,把4放到C中,C[] = {1, 2, 3, 4}
5與6比較,把5放到C中,C[] = {1, 2, 3, 4, 5}
6與7比較,把6放到C中,C[] = {1, 2, 3, 4, 5,6}
7與8比較,把7放到C中,C[] = {1, 2, 3, 4, 5, 6, 7}
最後的8不用比較,直接放到C中,C[] = {1, 2, 3, 4, 5, 6, 7, 8}
共比較了7次,即2n - 1次

18 C
從2022年開始,不可使用C和Pascal,只能使用C++

19 C
設P(A)表示至少兩個人生日在同一月份的概率,P(A’)表示四個人的生日都不在同一月份的概率,則P(A) = 1 - P(A’)
P(A’) = A(12, 4) / 12 ^ 4 = 12 * 11 * 10 * 9 / (12 * 12 * 12 * 12)= 55 / 96
P(A) = 1 - P(A’) = 41 / 96

20 B
奧斯卡是電影類的獎項
諾貝爾有六種獎項:物理、化學、生物和醫療、文學、經濟、和平
普利策是新聞類的獎項

二、問題求解

少兒程式設計答疑、演算法答疑請加微信307591841或QQ307591841
公眾號.jpg

相關文章