zoukankan      html  css  js  c++  java
  • NOIP2018初赛总结(提高组)(试题+答案+简要解析)

    NOIP2018初赛总结(提高组)

    更新完毕(纯手敲),如果有错误请在下面留言

    单选题

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

    A.((269)_{16})

    B.((617)_{10})

    C.((1151)_8)

    D.((1001101011)_2)

    答案:D

    实际上D比ABC要多2。这种题我一般先算2,8,16进制的,十进制难算,那三个很好互相转。

    T2.下列属于解释执行的程序设计语言是

    A.C

    B.C++

    C.Pascal

    D.Python

    答案:D

    常识题。前三项都是编译型语言。

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

    A.1983

    B.1984

    C.1985

    D.1986

    答案:B

    CCF颂歌题。凭感觉做题即可

    upd:附上官方地址

    背景:1984年邓小平指出:“计算机的普及要从娃娃做起。”中国计算机学会于1984年创办全国青少年计算机程序设计竞赛(简 称:NOI),当年参加竞赛的有8000多人。这一新的活动形式受到党和政府的关怀,得到社会各界的关注与支持。中央领导王震同志出席了首届竞赛发 奖大会,并对此项活动给予了充分肯定。从此每年一次NOI活动,吸引越来越多的青少年投身其中。十几年来,通过竞赛活动培养和发现了大批计算机爱好者,选 拔出了许多优秀的计算机后备人才。当年的许多选手已成为计算机硕士、博士,有的已经走上计算机科研岗位。

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

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

    B.(k^{h-1})

    C.(k^h)

    D.(displaystylefrac{k^{h-1}}{k-1})

    答案:A

    可以打表可以记结论,甚至你还可以现场推结论:等比数列求和。第0层的节点为1,第1层为k,第二层为(k^2),直到第(h)层为(k^h),等比数列求和公式为(frac{1-k^{h+1}}{1-k})即可选A。

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

    A.O(log n)

    B.O(n log n)

    C.O(n)

    D.O(n^2)

    答案:D

    NOIP2015初赛第?题

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

    A.(ad*bc*-)

    B.(-*ad*bc)

    C.(a*d-b*c)

    D.(-**adbc)

    答案:B

    卧槽慌得一批差点看成后缀表达式。可以直接模拟得到结果。

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

    A.1/2

    B.1/3

    C.2/3

    D.3/5

    答案:B

    可以通过几何概型+体积什么什么的求。建立一个三维坐标系Oxyz,x轴代表点A位置,y轴代表点B位置,z轴代表线段长度期望,那么长度的期望就是两个四面体拼起来的图形,顶点为(0,0,0),(1,0,0),(0,1,0),(0,0,1)和(1,1,0),(1,0,0),(0,1,0),(1,1,1)。这个几何体的体积为1/3(锥体体积为底面积乘以高再除以3),由于底面积为1,所以高度平均为1/3,即长度期望为1/3。zcysky的骗分思路也可以参考一下。

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

    A.Cn表示有n+1个节点的不同形态的二叉树的个数。

    B.Cn表示含n对括号的合法括号序列的个数。

    C.Cn表示长度为n的入栈序列对应的合法的出栈序列个数。

    D.Cn表示通过连接顶点而将n+2边的凸多边形分成三角形的方法个数。

    答案:A

    A选项应该是n而不是n+1。可以把n=1、n=2时候暴力带入。

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

    A.1:2

    B.2:1

    C.1:3

    D.1:1

    答案:D

    考虑如果某个人抽中蓝球,就让他的儿子取抽球,那么每个人抽中红球蓝球的概率相等,那么答案为D。

    T10.为了统计一个非负整数的二进制中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

    假设二进制末尾是100000的形式,-1之后就是011111,与之后就是000000,最后一个1就没了。这个B选项其实就是lowbit操作。

    不定项题

    T1.NOIP初赛中,选手可以带入考场的有

    A.笔

    B.橡皮

    C.手机(关机)

    D.草稿纸

    答案:AB

    详见CCF官方规则。一般是不允许带手机和草稿纸,各地规定不太一样呢。

    upd:附上官方规则的地址,本题考得是第12条。

    选手进入考场时,只许携带笔、橡皮等非电子文具入场。禁止携带任何电子产品或机器设备入场,无存储功能的手表除外;手机(关机)、U盘或移动硬盘、键盘、鼠标、闹钟、计算器、书籍、草稿纸及背包等物品必须存放在考场外。如有违规带入的,一经发现,NOI各省特派员可直接取消违规选手的参赛资格。

    T2.2-3树是一种特殊的树,它满足两个条件:

    1. 每个内部节点有两个或三个子节点;
    2. 所有的叶子节点到根的路径长度相同。

    如果一棵2-3树有10个叶节点,那么它可能有?个非叶节点。

    A.5

    B.6

    C.7

    D.8

    答案:CD

    考虑每一层的节点数是1->2->5->10和1->2->4->10的形式。

    T3.下列关于最短路算法的说法正确的有

    A.当图中不存在负权回路但是存在负权边时,Dijkstra算法不一定能求出源点到所有点的最短路。

    B.当图中不存在负权边时,调动多次Dijkstra算法能求出每对顶点间最短路径。

    C.图中存在负权回路时,调用一次Dijkstra算法也一定能求出源点到所有点的最短路。

    D.当图中不存在负权边时,调用一次Dijkstra算法不能用于每对顶点间的最短路计算。

    答案:ABD

    Dijkstra:单源最短路,不支持负权边。当然负权回路也是不行的

    T4.下列说法中,是树的性质的有

    A.无环

    B.任意两个节点之间有且只有一条简单路径

    C.有且只有一个简单环

    D.边的数目恰好是顶点数目-1

    答案:ABD

    树的性质常识题。

    T5.下列关于图灵奖的说法中,正确的有

    A.图灵奖是由电气和电子工程师协会(IEEE)设立的。

    B.目前获得该奖项的华人学者只有姚期智教授衽。

    C.其名称取自计算机科学的先驱、英国科学家艾伦·麦席森·图灵。

    D.它是计算机界最负盛名、最崇高的一个奖项,有“计算机界的诺贝尔奖”之称。

    答案:BCD

    图灵奖是美国的ACM协会创办的。

    问题求解

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

    已知

    1. 如果周末下雨,并且乙不去,则甲一定不去;
    2. 如果乙去,则丁一定去;
    3. 如果丙去,则丁一定不去;
    4. 如果丁不去,而且甲不去,则丙一定不去。

    如果周末丙去了,则甲(去了/没去),乙(去了/没去),丁(去了/没去),周末(下雨、没下雨)。

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

    根据3,丙去了,那么丁没去

    根据2的逆否,丁没去,乙一定没去

    根据4,丙去了,丁没去,那么甲一定去了//upd于12.13

    根据1,乙没去,甲去了,周末不下雨

    T2.方程(a*b=(a mathrm{or} b)*(a mathrm{and} b)),在a和b都取[0,31]中的整数时,共有?组解。(*表示乘法;or表示按位或运算;and表示按位与运算)

    答案:454

    介绍一个结论:(a mathrm{and} blemin(a,b)lemax(a,b)le a mathrm{or} b<2*max(a,b))

    最后一个小于号可能不太理解,因为乘以一个2一定要进位,a or b一定是不会进位的。前面的不等号很好理解

    那么对答案的贡献形式一定是(left{egin{aligned}a mathrm{and} b=min(a,b)\a mathrm{or} b=max(a,b)end{aligned} ight.)。那么最小值的二进制一定是最大值的二进制的子集。枚举所有二进制可能的位数,由于要删去(a=b)的重复情况,那么答案为(displaystyle2 imesleft(sum_{i=0}^5mathrm{C}_{5}^i imes2^i ight)-32=454)

    阅读程序写结果

    程序自己打的,大括号换了行否则太不顺眼了。。。

    #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

    打表找0到14中所有数平方对15取模判断是否为1即可,最后是1,4,11,14是答案。建议验算几遍,以免出错。

    #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
    ", cnt);
        return 0;
    }
    

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

    输出:6

    置换的阶的计数。我tm一开始看成11个元素的置换了,把开头的10也算进去了算成了3。这个动手模拟很简单的。

    #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

    寻找字符串中独一无二的子串的个数。magic函数其实是[l,r]区间内的一个BKDRHash。什么鬼名字。话说CCF的程序效率太低了吧

    #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('
    '); else putchar(' ');
        }
        return 0;
    }
    

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

    输出1:2 1 3 5 6 4

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

    输出2:3 2 5 6 1 4

    不难看出本题是求排列的下t个排列,CCF这个程序实现的效率太菜了吧,竟然从初始排列不断枚举,直到排列大于给定排列。

    对于输入1,可以直接手推

    对于输入2,正解应该是康托展开(了解一下),但是也可以一次跳阶乘次步。例如当后3位是单调递减的时候,可以直接跳3的阶乘次步,直接转移到下一个后3位是单调递减的情况。能节省中间模拟的时间,这种方法对不会康托展开的同学(比如我)适用

    完善程序

    T1.对于一个1到n的排列P(即1到n中每一个数在P中出现了恰好一次),令(q_i)为第i个位置之后第一个比(P_i)值更大的位置,如果不存在这样的位置,则(q_i=n+1)。举例来说,如果n=5且P为1 5 4 2 3,则q为2 6 6 5 6。

    下列程序读入了排列P,使用双向链表求解了答案。试补全程序。(第二空2分,其余3分)

    数据范围(1le nle10^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)____;//a[x] = i
        }
        for (int i = 1; i <= n; ++i)
        {
            R[i] = ____(2)____;//i + 1
            L[i] = i - 1;
        }
        for (int i = 1; i <= n; ++i)
        {
            L[____(3)____] = L[a[i]];//R[a[i]]
            R[L[a[i]]] = R[____(4)____];//a[i]
        }
        for (int i = 1; i <= n; ++i)
        {
            cout << ____(5)____ << " ";//R[i]
        }
        cout << endl;
        return 0;
    }
    

    1.a[i]表示大小为i的元素所在位置。

    2.对称地写下一行的东西。链表的下一个元素。

    3.对称地写下一行的东西。删除链表中本元素,把本元素右边元素的左指针跨过本元素指向左侧元素。

    4.还是对称。把左边元素右指针指向右侧元素。

    5.输出第i个数的后继元素即第一个比他大的元素,即R[i]。

    T2.一只小猪要买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)____)//0.95 * a[i] <= b[i]
            {
                put_a[i] = true;
                total_a += a[i];
            }
            else
            {
                put_a[i] = false;
                total_b += b[i];
            }
        }
        if (____(2)____)//total_a >= threshold
        {
            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)//total_a + j + a[i]
                        ans = min(ans, (total_a + j + a[i]) * 0.95 + ____(4)____);//f[j] + total_b - total_b_prefix
                    f[j] = min(f[j] + b[i], j >= a[i] ? ____(5)____ : Inf);//f[j - a[i]]
                }
            }
        }
        printf("%.2f", ans);
        return 0;
    }
    

    一个奇怪的DP。

    1.如果是a[i]<=b[i],那么要上面的统计有啥用。这里的循环其实是在假定需要打折的情况下,先挑选已经钦定的a[i]的物品。

    2.判断如果打折,直接购买便宜的a是否已经ok了。如果是就不需要再舍弃b购买一个较贵的a了,直接输出即可。

    3.注意到下面是total_a + j + a[i]乘的0.95,那么这个一定是a的总价,那么它一定要大于等于50000。

    4.观察下面的min,f[j]+b[i]说明f数组记录的是和b的价格有关的,而且它必须要出现,那么就放到这里。注意到total_b_prefix和total_b没有用过,说明他俩必须要用上,由于prefix是前缀,所以让total_b减去total_b_prefix即可。

    5.由于j>=a[i],那么j-a[i]>=0,考虑我们的背包转移,可以大胆猜想这里填f[j-a[i]]。

    本题实际上的状态是f[j]代表在前i个物品中,购买a店物品j元情况下购买b店物品的最小价值。total_a+j+a[i]代表买所有钦定要买的+额外需要买的+这次买的,f[j]+total_b-total_b_prefix是指i到n中所有选b,前面按照f[j]的状态取,b的价格。最后f[j]和取这次的b[i]与从j-a[i]转移过来去一个min,表示j这个状态取b还是取a。


    总结:这次考试我拿了95分,总体来说题和去年水平差不多,这套题还是比较注重思维能力吧,当然不少了CCF颂歌题,“常识”题。希望大家参加NOIP2018复赛时候RP++吧。

  • 相关阅读:
    easy ui 表单ajax和from两种提交数据方法
    easy ui 下拉级联效果 ,下拉框绑定数据select控件
    easy ui 下拉框绑定数据select控件
    easy ui 异步上传文件,跨域
    easy ui 菜单和按钮(Menu and Button)
    HTTP 错误 404.3
    EXTJS4.2 后台管理菜单栏
    HTML 背景图片自适应
    easy ui 表单元素input控件后面加说明(红色)
    EXTJS 4.2 添加滚动条
  • 原文地址:https://www.cnblogs.com/oier/p/9783787.html
Copyright © 2011-2022 走看看