NOIP2018TG初(baozha)赛

本文解析了NOIP2018初赛的多项选择题与问题求解题,涵盖进制转换、算法设计、数据结构、程序设计等核心知识点,深入分析了各题目的解题思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

NOIP2018TG初赛解析

一、单项选择题(共10 题,每题2 分,共计20 分;每题有且仅有一个正确选项)

1.下列四个不同进制的数中,与其它三项数值上不相等的是( )。

A. (269)16
B. (617)10
C. (1151)8
D. (1001101011)2

D

A=617 C=617 D=619

2.下列属于解释执行的程序设计语言是( )。

A. C
B. C++
C. Pascal
D. Python

D

Python是解释性语言,其他都是编译性语言

3.中国计算机学会于( )年创办全国青少年计算机程序设计竞赛。

A. 1983
B. 1984
C. 1985
D. 1986

B

4.设根节点深度为0,一棵深度为h 的满k(k>1)叉树,即除最后一层无任何子节点外,每一层上的所有结点都有k 个子结点的树,共有( )个结点。

A. \((k^{h+1} - 1) / (k - 1)\)

B. \(k^h-1\)

C. \(k^h\)

D. \((k^{h-1}) / (k - 1)\)

A

找规律计算。

5.设某算法的时间复杂度函数的递推方程是T(n) = T(n - 1) + n(n 为正整数)及T(0) = 1,则该算法的时间复杂度为( )。

D

常识问题。

A. O(log n) B. O(n log n) C. O(n) D. O(n2)

6.表达式a * d - b * c 的前缀形式是( )。

A. a d * b c * -
B. - * a d * b c
C. a * d - b * c
D. - * * a d b c

B

以中序遍历构建表达式树,再对该树后序遍历。

7.在一条长度为1 的线段上随机取两个点,则以这两个点为端点的线段的期望长度是( )。

A. 1 / 2
B. 1 / 3
C. 2 / 3
D. 3 / 5

Unknown

Unknown

8.关于Catalan 数Cn = (2n)! / (n + 1)! / n!,下列说法中错误的是( )。

A. Cn 表示有n + 1 个结点的不同形态的二叉树的个数。
B. Cn 表示含n 对括号的合法括号序列的个数。
C. Cn 表示长度为n 的入栈序列对应的合法出栈序列个数。
D. Cn 表示通过连接顶点而将n + 2 边的凸多边形分成三角形的方法个数。

A

\(C_n\)表示有\(n\)个结点的不同形态的二叉树的个数。

9.假设一台抽奖机中有红、蓝两色的球,任意时刻按下抽奖按钮,都会等概率获得红球或蓝球之一。有足够多的人每人都用这台抽奖机抽奖,假如他们的策略均为:抽中蓝球则继续抽球,抽中红球则停止。最后每个人都把自己获得的所有球放到一个大箱子里,最终大箱子里的红球与蓝球的比例接近于
( )。

A. 1 : 2
B. 2 : 1
C. 1 : 3
D. 1 : 1

D

极限法:若抽奖机里的球被全部抽完,则答案必为\(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

Dijkstra算法能够使用的前提是不存在负环,不是负权边。调用 顶点个数 次Dijkstra 算法或spfa 算法,或调用一次floyd 算法能用于每对顶点间最短路计算。

4.下列说法中,是树的性质的有( )。

A. 无环
B. 任意两个结点之间有且只有一条简单路径
C. 有且只有一个简单环
D. 边的数目恰是顶点数目减1

ABD

树的概念。

5.下列关于图灵奖的说法中,正确的有( )。

A. 图灵奖是由电气和电子工程师协会(IEEE)设立的。
B. 目前获得该奖项的华人学者只有姚期智教授一人。
C. 其名称取自计算机科学的先驱、英国科学家艾伦·麦席森·图灵。
D. 它是计算机界最负盛名、最崇高的一个奖项,有“计算机界的诺贝尔奖”之称。

BCD

图灵奖由美国计算机协会(ACM)于1966年设立。

三、问题求解(共2 题,每题5 分,共计10 分)
1.甲乙丙丁四人在考虑周末要不要外出郊游。
已知①如果周末下雨,并且乙不去,则甲一定不去;②如果乙去,则丁一定去;③如果丙去,则丁一定不去;④如果丁不去,而且甲不去,则丙一定不去。如果周末丙去了,则甲(去了/没去)(1 分),乙(去
了/没去)(1 分),丁(去了/没去)(1 分),周末(下雨/没下雨)(2 分)。

去了 没去 没去 没下雨

小学奥数题 现在的小学生太强了
若周末不下雨,且丙去,则丁不去,所以乙不去,甲去。

2.方程 \(a*b = (a | b) * (a \& b)\),在 a,b 都取 [0, 31] 中的整数时,共有_组解。

454

Unknown

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

#include <cstdio>
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

对于\(i∈[1,14],i^2\%15==1\)\(i\)的个数。

输出:

#include <cstdio>
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

暴力模拟即可。
#include <iostream>
using namespace std;
string s;
long long magic(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

本题就是要找满足条件的字符串\(S\)的子串个数,设字符串\(S\)的一个子串\(S_{l_1,r_1}\),使得存在一个不同的子串\(S_{l_2,r_2}\),满足\(S_{l_1,r_1}==S_{l_2,r_2}\)
#include <cstdio>
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;
}
bool getPermutation(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 3 2

输出1:

输入2:6 200 1 5 3 4 2 6

输出2:

2 1 3 5 6 4

3 2 5 6 1 4

找到输入排列以后的第\(t\)个排列,运用阶乘知识枚举即可。

五、完善程序(共2 题,每题14 分,共计28 分)
1.对于一个1到?的排列?(即1到?中每一个数在?中出现了恰好一次),令??为第?个位置之后第一个比??值更大的位置,如果不存在这样的位置,则?? = ? +1。举例来说,如果? = 5且?为1 5 4 2 3,则?为2 6 6 5 6。
下列程序读入了排列?,使用双向链表求解了答案。试补全程序。(第二空2 分,其余3 分)
数据范围\(1 \le n \le 10^5\)

#include <iostream>
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;
        (1) ;
    }
    for (int i = 1; i <= n; ++i) {
        R[i] = (2) ;
        L[i] = i - 1;
    }
    for (int i = 1; i <= n; ++i) {
        L[ (3) ] = L[a[i]];
        R[L[a[i]]] = R[ (4) ];
    }
    for (int i = 1; i <= n; ++i) {
        cout << (5) << " ";
    }
    cout << endl;
    return 0;
}
  1. a[x]=i
  2. i+1
  3. R[a[i]]
  4. a[i]
  5. R[i]

    使用对称法
    Unknown

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;
int f[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];
        else total_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);
        return 0;
    }
    f[0] = 0;
    for (int i = 1; i < threshold; ++i)
        f[i] = Inf;
    int total_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);
    return 0;
}
  1. a[i]*0.95<=b[i]
  2. total_a>=threshold
  3. total_a+j+a[i]
  4. f[j]+total_b-total_b_prefix
  5. f[j-a[i]]

    1.2.明显的贪心
    3.4.5.背包

参考答案:
37701.png

总结

会做的题目一定要保证做对!
估分估出来六十几,结果考了71分,分数线68…………

while(1) puts("Yes");

转载于:https://www.cnblogs.com/BlogOfchc1234567890/p/9863170.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值