NOIP 2018 提高組初賽試題 題目+答案+簡要解析


一、單項選擇題(共 10  題,每題 2  分,共計 20  分; 每題有且僅有一個正確選項)
 
 
 
1. 下列四個不同進制的數中,與其它三項數值上不相等的是( )。
A. (269) 16
B. (617) 10
C. (1151) 8
D. (1001101011) 2
 
答案:D
 
解析:進制轉換,把所有的選項都轉換成相同的進制即可。 至於轉成幾進制,看個人喜好
 
2. 下列屬於解釋執行的程序設計語言是( )。
A. C
B. C++
C. Pascal
D. Python
 
答案:D
 
解析:可以理解為:需要編譯的就是非解釋性語言。本人印象最深的解釋型語言是Java,有什么錯寫完一句就報出來。
C,C++,pascal都是需要編譯的語言,就是非解釋性語言
而python是交互式的,也是解釋性語言
 
 
3. 中國計算機學會於( )年創辦全國青少年計算機程序設計競賽。
A. 1983
B. 1984
C. 1985
D. 1986
 
答案:B
 
解析:???我也不知道
 
4. 設根節點深度為 0,一棵深度為 h 的滿 k(k>1)叉樹,即除最后一層無任何
子節點外,每一層上的所有結點都有 k 個子結點的樹,共有( )個結點。 

(k^{h+1}-1)/(k-1)(kh+11)/(k1)

k^{h-1}kh1

k^hkh

(k^{h-1})/(k-1)(kh1)/(k1)

 
答案:A
 
解析:等比數列求和。我是蒟蒻不會?多畫兩棵樹自己試(逃
 
 
5. 設某算法的時間復雜度函數的遞推方程是 T(n) = T(n - 1) + n(n 為正整數)
及 T(0) = 1,則該算法的時間復雜度為( )。
 
       O(n^2)
 
答案:D
 
解析:
NOIP初賽中的時間復雜度分析題就是授人以魚,考人以魛魢魨魷䰾魴鮋鮊魺鮃鮁鯰鮍鮓鮒鮐鱸鮑鱟鮺鮜鱠鰂鮳鮦鯗鮫鮚鱭鮮鱘鮪鮞鮭鯀鯒鮶鯽鯇鰹鯊鱺鰱鯉鯁鰣鰷鯴鯕鰺鯝鯰鯧鯪鯖鯢鯤鯫鯡鯔鯛鯨鰠鯿鰮鯷鰏鱝鰁鱂鰓鱷鱨鰉鰃鰒鰍鰈鰲鰜鰨鰥鰟鰩鰭鰵鰼鱈鰳鱅鰻䲁鰾鱉鱖鱒鱗鱔鱤鱯鱧鱣鳤。
 引自洛谷日報(逃
但我覺的可能就是求和……要把式子展開,變成
 1+1+2+3+...+(n-1)+n=1+n*(n+1)/2然后忽略常數復雜度總和變成n^2
 
     - * * a d b c
答案:B
 
解析:先建一棵表達式樹,先序遍歷就是前綴表達式
 
 
7. 在一條長度為 1 的線段上隨機取兩個點,則以這兩個點為端點的線段的期望
長度是( )。
A. 1 / 2
B. 1 / 3
C. 2 / 3
D. 3 / 5
 
答案:B
 
解析:全靠猜
我們設這個區間[l,r]l=0,因題目0<r<1
0-r長度的期望為1/2,顯然l-r的期望會比0-r小……所以就是1/3了(
 
 
8. 關於 Catalan 數 Cn = (2n)! / (n + 1)! / n!,下列說法中錯誤的是( )。
A. Cn 表示有 n + 1 個結點的不同形態的二叉樹的個數。
B. Cn 表示含 n 對括號的合法括號序列的個數。
C. Cn 表示長度為 n 的入棧序列對應的合法出棧序列個數。
D. Cn 表示通過連接頂點而將 n + 2 邊的凸多邊形分成三角形的方法個數。
 
答案:A
 
解析:基本知識?反正我不會QwQ
找個數帶進去就行
 
 
9. 假設一台抽獎機中有紅、藍兩色的球,任意時刻按下抽獎按鈕,都會等概率
獲得紅球或藍球之一。有足夠多的人每人都用這台抽獎機抽獎,假如他們的
策略均為:抽中藍球則繼續抽球,抽中紅球則停止。最后每個人都把自己獲
得的所有球放到一個大箱子里,最終大箱子里的紅球與藍球的比例接近於
( )。
A. 1 : 2
B. 2 : 1
C. 1 : 3
D. 1 : 1
 
答案:D
 
解析:算出每一輪拿到紅球的期望為1,拿到藍球必定1個,所以比例會接近1:1
 
 
10. 為了統計一個非負整數的二進制形式中 1 的個數,代碼如下:
int CountBit(int x)
{
  int ret = 0;
  while (x)
  {
      ret++;
      ________;
  }
  return ret;
}
則空格內要填入的語句是( )。
A. x >>= 1
B. x &= x - 1
C. x |= x >> 1
D. x <<= 1
 
答案:B
 
解析:排除法+手算
 
 
二 、 不定 項選擇題(共 5  題,每題 2  分,共計 10  分 ;每題有一個或多個正確選
項,多選或少選均不得分 )
 
 
1. NOIP 初賽中,選手可以帶入考場的有( )。
A. 筆
B. 橡皮
C. 手機(關機)
D. 草稿紙
 
答案:AB
 
解析:憑感覺
 
 
2. 2-3 樹是一種特殊的樹,它滿足兩個條件:
(1)每個內部結點有兩個或三個子結點;
(2)所有的葉結點到根的路徑長度相同。
如果一棵 2-3 樹有 10 個葉結點,那么它可能有( )個非葉結點。
A. 5
B. 6
C. 7
D. 8
 
答案:CD
 
解析:自己構造樹
 
 
3. 下列關於最短路算法的說法正確的有( )。
A. 當圖中不存在負權回路但是存在負權邊時,Dijkstra 算法不一定能求出源
點到所有點的最短路。
B. 當圖中不存在負權邊時,調用多次 Dijkstra 算法能求出每對頂點間最短路
徑。
C. 圖中存在負權回路時,調用一次 Dijkstra 算法也一定能求出源點到所有點
的最短路。
D. 當圖中不存在負權邊時,調用一次 Dijkstra 算法不能用於每對頂點間最短
路計算。
 
答案:ABD
 
解析:dijstra算法不適用於負權圖,而且它用於求單點到其他點的最短路
 
 
4. 下列說法中,是樹的性質的有( )。
A. 無環
B. 任意兩個結點之間有且只有一條簡單路徑
C. 有且只有一個簡單環
D. 邊的數目恰是頂點數目減 1
 
答案:ABD
 
解析:樹的基本知識
 
 
5. 下列關於圖靈獎的說法中,正確的有( )。
A. 圖靈獎是由電氣和電子工程師協會(IEEE)設立的。
B. 目前獲得該獎項的華人學者只有姚期智教授一人。
C. 其名稱取自計算機科學的先驅、英國科學家艾倫·麥席森·圖靈。
D. 它是計算機界最負盛名、最崇高的一個獎項,有“計算機界的諾貝爾獎”
之稱。
 
答案:BCD
 
解析:你覺得A能對嗎
--------------------- 

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

 

1. 甲乙丙丁四人在考慮周末要不要外出郊游。

已知①如果周末下雨,並且乙不去,則甲一定不去;②如果乙去,則丁一定去;③如果丙去,則丁一定不去;④如果丁不去,而且甲不去,則丙一定不去。如果周末丙去了,則甲_____(去了/沒去)(1分),乙_____(去了/沒去)(1分),丁_____(去了/沒去)(1分),周末_____(下雨/沒下雨)(2分)。

 

答案:去了,沒去,沒去,沒下雨

 解析:送分題,根據條件判斷即可

 

2. 方程 a*b =(a or b)  *  (a andb),在a, b都取[0、31]中的整數時,共有______組解。(*表示乘法;or表示按位或運算;and表示按位與運算)

 

解析:使得a|b==max(a,b),a&b==min(a,b)

顯然,a,b存在子集關系時上面的式子才能成立。

例如:1011|1001=1011=max(1011,1001)

可以自己舉例驗證QwQ

我們設b是a的子集,枚舉a在二進制下有多少個1,即從5里面取i個1,i從0到5。每個i都是一個C(5, i)

接着枚舉子集,有2^i中方案(每一個1都看看放還是不放)

C(5,0)*2^0 +C(5,1)*2^1+…+C(5,5)*2^5

= 1*1 + 5*2 + 10*4 + 10*8 + 5*16 + 1*32

= 243

最后,由於我們限制了a>b,所以答案要*2

但是a==b的情況會被多算,所以答案減去32

最后結果:2*243 – 32 = 452

 

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

1.

#include

int main() {

int x;

scanf("%d", &x);

int res = 0;

for (int i = 0; i < x; ++i) {

    if (i * i % x == 1) {

        ++res;

    }

}

printf("%d", res);

return 0;

}

輸入:15

輸出:4

解析:簡單模擬

2.

#include

int n, d[100];

bool v[100];

int main() {

scanf("%d", &n);

for (int i = 0; i < n; ++i) {

    scanf("%d", d + i);

    v[i] = false;

}

int cnt = 0;

for (int i = 0; i < n; ++i) {

    if (!v[i]) {

        for (int j = i; !v[j]; j = d[j]) {

            v[j] = true;

        }

        ++cnt;

    }

}

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

return 0;

}

輸入:10 7 1 4 3 2 5 9 8 0 6

輸出:6

 

解析:繼續模擬(逃

 

3.

#include

using namespace std;

string s;

long longmagic(int l, int r) {

long long ans = 0;

for (int i = l; i <= r; ++i) {

    ans = ans * 4 + s[i] - 'a' + 1;

}

return ans;

}

int main() {

cin >> s;

int len = s.length();

int ans = 0;

for (int l1 = 0; l1 < len; ++l1) {

    for (int r1 = l1; r1 < len; ++r1) {

        bool bo = true;

        for (int l2 = 0; l2 < len; ++l2) {

            for (int r2 = l2; r2 < len; ++r2) {

                if (magic(l1, r1) == magic(l2, r2)&& (l1 != l2 || r1 != r2)) {

                    bo = false;

                }

            }

        }

        if (bo) {

            ans += 1;

        }

    }

}

cout << ans << endl;

return 0;

}

輸入:abacaba

輸出:16

 

解析:magic(l,r)是l-r的hash,枚舉兩個子串,答案就是不重復出現的子串個數,手動枚舉。

 

4.

#include

using namespace std;

const int N =110;

bool isUse[N];

int n, t;

int a[N], b[N];

bool isSmall() {

for (int i = 1; i <= n; ++i)

    if (a[i] != b[i]) return a[i] < b[i];

return false;

}

boolgetPermutation(int pos) {

if (pos > n) {

    return isSmall();

}

for (int i = 1; i <= n; ++i) {

    if (!isUse[i]) {

        b[pos] = i; isUse[i] = true;

        if (getPermutation(pos + 1)) {

            return true;

        }

        isUse[i] = false;

    }

}

return false;

}

void getNext() {

for (int i = 1; i <= n; ++i) {

    isUse[i] = false;

}

getPermutation(1);

for (int i = 1; i <= n; ++i) {

    a[i] = b[i];

}

}

int main() {

scanf("%d%d", &n, &t);

for (int i = 1; i <= n; ++i) {

    scanf("%d", &a[i]);

}

for (int i = 1; i <= t; ++i) {

    getNext();

}

for (int i = 1; i <= n; ++i) {

    printf("%d", a[i]);

    if (i == n) putchar('\n'); else putchar('');

}

return 0;

}

輸入1:6 10 1 6 4 5 32

輸出 1:2 1 3 5 6 4 (3 分)

輸入2:6 200 1 5 3 4 26

輸出 2:3 2 5 6 1 4 (5 分)

 

解析:這一大堆函數就是求這個排列的下一個……手算即可(當然如果你覺得200算不出來可以使用康托展開)



五、完善程序(共 2 題,每題 14 分,共計 28 分)

 

1. 對於一個1到n的排列p(即1到n中每一個數在p中出現了恰好一次),令qi為第i個位置之后第一個比pi值更大的位置,如果不存在這樣的位置,則qi =n+1。

舉例來說,如果n=5且p為1 5 4 2 3,則q為2 6 6 5 6。

下列程序讀入了排列p,使用雙向鏈表求解了答案。試補全程序。(第二空2分,其余3分)

數據范圍 1 ≤ n ≤ 105。

 

#include

using namespace std;

const int N =100010;

int n;

int L[N], R[N],a[N];

int main() {

cin >> n;

for (int i = 1; i <= n; ++i) {

    int x;

    cin >> x;

    a[x] = i ;

}

for (int i = 1; i <= n; ++i) {

    R[i]= i + 1;

    L[i] = i - 1;

}

for (int i = 1; i <= n; ++i) {

    L[ R[a[i]]] = L[a[i]];

    R[L[a[i]]] = R[a[i] ];

}

for (int i = 1; i <= n; ++i) {

    cout << R[i]<< " ";

}

cout << endl;

return 0;

}

解析:

純靠猜。1空發現沒有直接讀入,肯定有鬼……瞎猜一種方法就行

2空仿寫下句……

3,4空互相仿寫……

5空我們肯定要求這個數右邊比他大的數的位置,所以輸出R

當然我蒻看不懂,有心情研究的julao們可以再去找找……

 

2. 一只小豬要買 N 件物品(N 不超過 1000)。

它要買的所有物品在兩家商店里都有賣。第 i 件物品在第一家商店的價格是 a[i],在第二家商店的價格是 b[i],兩個價格都不小於 0 且不超過 10000。如果在第一家商店買的物品的總額不少於 50000,那么在第一家店買的物品都可以打 95 折(價格變為原來的 0.95 倍)。

求小豬買齊所有物品所需最少的總額。

輸入:第一行一個數 N。接下來 N 行,每行兩個數。第 i 行的兩個數分別代表 a[i],b[i]。

輸出:輸出一行一個數,表示最少需要的總額,保留兩位小數。

試補全程序。(第一空 2 分,其余 3 分)

 

#include <cstdio>

#include <algorithm>

using namespace std;

 

const int Inf = 1000000000;

const int threshold = 50000;

const int maxn = 1000;

 

int n, a[maxn], b[maxn];

bool put_a[maxn];

int total_a,total_b;

double ans;

intf[threshold];

 

int main() {

  //第一部分

  scanf("%d",&n);

  total_a= total_b = 0;

  for(int i = 0; i < n; ++i) {

    scanf("%d%d",a + i, b + i);

    if(a[i] <= b[i]) total_a += a[i];

    elsetotal_b += b[i];

  }

  ans =total_a + total_b;

  total_a= total_b = 0;

 


  for(int i = 0; i < n; ++i) {

    if( (1) ) {

      put_a[i]= true;

      total_a+= a[i];

    }else {

      put_a[i]= false;

      total_b+= b[i];

    }

  }

  if ((2) ) {

    printf("%.2f",total_a * 0.95 + total_b);

    return0;

  }

 
//第二部分

  f[0]= 0;

  for(int i = 1; i < threshold; ++i)

    f[i]= Inf;

  inttotal_b_prefix = 0;

  for(int i = 0; i < n; ++i)

    if (!put_a[i]) {

      total_b_prefix += b[i];

      for (int j = threshold - 1; j >= 0; --j) {

 if ( (3) >= threshold && f[j] != Inf)

   ans = min(ans, (total_a + j +a[i]) * 0.95+ (4) );

        f[j] = min(f[j] + b[i], j >= a[i] ? (5) :Inf);

      }

    }

  printf("%.2f",ans);

  return0;

}

 

解析:

代碼分為兩個部分。

第一部分是一個貪心,我們假設滿足了優惠條件,按照折后價格進行貪心,如果結果滿足了優惠條件就直接輸出,此時如果放棄某些b商品來買a不會再有更優策略

第二部分是一個dp……策略就是把原先買了b的東西買a以獲得折扣

f[i,j]表示前i個物品,在額外在A店花了j元的情況下,購買B店物品花費的最小值。i呢?想想你的01背包是怎么優化的。

3空是一個轉移判斷條件,tot_a+j+a[i]是在a店話費的總錢數(本來花的錢+前面改了的錢+當前物品價格)

4空表示在b商店買的物品總價, total_b  + f[j] -  total_b_prefix

5空更新,看看這個商品在a商店買還是b商店買

 

太毒瘤了QwQ


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM