NOIP2008普及组初赛难点整理

选择题

T5. 完全二叉树共有 2 × N − 1 2\times N-1 2×N1 个结点,则它的叶结点数是( N)。

【解析】有 2 × N − 1 2\times N-1 2×N1 个结点的完全二叉树,最后一个拥有孩子结点的父结点的编号为 ⌊ 2 N − 1 2 ⌋ = N − 1 \lfloor \frac{2N-1}{2}\rfloor=N-1 22N1=N1,那么叶结点数 = 2 × N − 1 − ( N − 1 ) = N =2\times N - 1 - (N - 1) = N =2×N1(N1)=N

T16. 面向对象程序设计(Object-Oriented Programming)是一种程序设计的方法论,它将对象作为程序的基本单元,将数据和程序封装在对象中,以提高软件的重用性、灵活性和扩展性。下面关于面向对象程序设计的说法中,不正确的是( )。

【解析】选项:面向对象程序设计通常采用自顶向下设计方法进行设计,是错误的。程序设计的方法包括:结构化设计面向对象设计方法。结构化的程序设计通常采用自顶向下的设计方法,逐步求精。可以说,是大问题化成小问题,逐个求解。

T17. 在 32 × 32 32\times32 32×32 点阵的“字库”中,汉字“北”与“京”的字模占用字节数之和是(256)。

【解析】 在 32 × 32 32\times32 32×32
点阵的“字库”中,每个字模占用的字节数为: 32 × 32 ÷ 8 = 128 32\times32\div8=128 32×32÷8=128。汉字“北”与“京”的字模占用字节数之和是256

问题求解

T2. 书架上有 4 本不同的书 A、B、C、D。其中 A 和 B 是红皮的,C 和 D 是黑皮的。把这 4 本书摆在书架上,满足所有黑皮的书都排在一起的摆法有(12)种。满足 A 必须比 C 靠左,所有红皮的书要摆放在一起,所有黑皮的书要摆放在一起,共有(4)种摆法。
【解析】

  • 第一问满足所有黑皮的书都排在一起,可以使用捆绑和插空法,A、B排列后有3个空,将C、D排列后插入即可,答案为: P 2 2 × P 2 2 × C 3 1 = 12 P_2^2\times P_2^2\times C_3^1=12 P22×P22×C31=12
  • 第二问,红皮的书要摆放在一起、黑皮的书要摆放在一起,使用捆绑法,即先将A、B捆绑排列,C、D捆绑排列,然后再将两个整体排列,此时A 必须比 C 靠左的排列占了一半,所以答案为: P 2 2 × P 2 2 × 2 ÷ 2 = 4 P_2^2\times P_2^2\times 2\div2=4 P22×P22×2÷2=4

阅读程序

T4.

#include<iostream>
#include<cstring>
using namespace std;
#define MAX 100
void solve(char first[], int spos_f, int epos_f, char mid[], int spos_m, int epos_m)
{
    
    
    int i, root_m;
    if (spos_f > epos_f)
        return;
    for (i = spos_m; i <= epos_m; i++)
        if (first[spos_f] == mid[i])
        {
    
    
            root_m = i;
            break;
        }
    solve(first, spos_f + 1, spos_f + (root_m - spos_m), mid, spos_m, root_m - 1);
    solve(first, spos_f + (root_m - spos_m) + 1, epos_f, mid, root_m + 1, epos_m);
    cout << first[spos_f];
}

int main()
{
    
    
    char first[MAX], mid[MAX];
    int len;
    cin >> len;
    cin >> first >> mid;
    solve(first, 0, len - 1, mid , 0, len - 1);
    cout << endl;
    return 0;
}

输入:

7
ABDCEGF
BDAGECF

输出:

DBGEFCA

【解析】输入二叉树的先根遍历序列和后根遍历序列,求后根遍历序列。

完善程序

T1.(字符串替换)给定一个字符串 S(S 仅包含大小写字母),下面的程序将 S 中的每个字母用规定的字母替换,并输出 S 经过替换后的结果。程序的输入是两个字符串,第一个字符串是给定的字符串 S,第二个字符串 S’ 由 26 个字母组成,它是 a−z 的任一排列,大小写不定,S’ 规定了每个字母对应的替换字母:S 中的第一个字母是字母 A 和 a 的替换字母,即 S 中的 A 用该字母的大写替换, S 中的 a 用该字母的小写替换;S’ 中的第二个字母是字母 B 和 b 的替换字母,即 S 中的 B 用该字母的大写替换,S 中的 b 用该字母的小写替换;……以此类推。

#include <iostream>
#include <string.h>
char change[26], str[5000];
using namespace std;
void CheckChangeRule()
{
    
    
    int i;
    for (i = 0;i < 26; i++)
    {
    
    
        if ()
               change[i] -= 'A' - 'a';
    }
}
void ChangeString()
{
    
    
    int i;
    for (i = 0;i <strlen(str); i++)
    {
    
    
          if ()
                str[i] = change[str[i] - 'A'] -'a' + 'A';
          else}
}
int main()
{
    
    
    int i;
    cin >> str ;
    cin >> change;
    CheckChangeRule();
    ④
    cout << str << endl;
    return 0;
}

【解析】

  • 空①,函数CheckChangeRule()将字符数组change中所有大写字符转换为小写。如果change[i]为大写字符,需要转换为小写,此空应填change[i]>='A' && change[i]<='Z'
  • 空②,如果要替换的是大写字符,即str[i]>='A' && str[i]<='Z'
  • 空③,替换小写字符,str[i] = change[str[i] - 'a'];
  • 空④,调用函数ChangeString()进行替换。

T2. (找第 k 大的数)给定一个长度为 1,000,000 的无序正整数序列, 以及另一个数 n ( 1 ≤ n ≤ 1000000 1\le n\le1000000 1n1000000), 然后以类似快速排序的方法找到序列中第 n 大的数(关于第 n 大的数:例如序列 {1,2,3,4,5,6} 中第 3 大的数是 4)。

#include <iostream>
using namespace std;
int a[1000001],n,ans = -1;
void swap(int &a,int &b)
{
    
    
    int c;
    c = a; a = b; b = c;
}
int FindKth(int left, int right, int n)
{
    
    
    int tmp, value, i, j;
    if (left == right) return left;
    tmp = rand()% (right - left) + left;
    swap(a[tmp], a[left]);
    value = ①
    i = left;
    j = right;
    while (i < j)
    {
    
    
        while (i < j &&) j --;
        if (i < j) {
    
     a[i] = a[j]; i++; } else break;
        while (i < j &&) i++;
        if (i < j) {
    
     a[j] = a[i]; j--; } else break;
    }if (i < n) return  FindKth();
    if (i > n) returnreturn i;
}
int main()
{
    
    
    int i;
    int m = 1000000;
    for (i = 1; i <= m; i++)
        cin >> a[i];
    cin >> n;
    ans = FindKth(1, m, n);
    cout << a[ans];
    return 0;
}

【解析】通过快速排序的思想,查找第n大的数。根据输出cout << a[ans];,可以确定是将序列按照从大到小的顺序进行排列。函数FindKth()将数组分成两部分,左边由大于等于value的数组成,右边由小于value的数组成。

  • 空①,设置基准值value = a[left];
  • 空②,找到右边第一个大于等于value的位置,将该位置的数放到i位置,此空应填a[j]<value
  • 空③,找到左边第一个小于等于value的位置,将该位置的数放到j位置,此空应填a[j]>value
  • 空④,将value放入到i位置,将数组分为两部分,此空应填a[i]=value;
  • 空⑤,如果i<n,到右边部分继续查找第n大的数,此空应填i+1,rigth,n
  • 空⑥,如果i>n,到左边部分继续查找第n大的数,此空应填FindKth(left,i-1,n)

猜你喜欢

转载自blog.csdn.net/qiaoxinwei/article/details/108736966