NOIP2017普及组初赛难点整理

选择题

  1. 2017 2017 2017 10 10 10 1 1 1 日是星期日, 1999 1999 1999 10 10 10 1 1 1 日是( )。
    A. 星期三
    B. 星期二
    C. 星期日
    D. 星期五

【解析】 1999 1999 1999 2017 2017 2017年一共是 18 18 18年, 18 × 365   % 7 = ( 18 % 7 × 365 % 7 ) % 7 = 4 18\times 365 \ \% 7=(18\%7\times365\%7)\%7=4 18×365 %7=(18%7×365%7)%7=4,中间有 5 5 5个闰年: 2000 , 2004 , 2008 , 2012 , 2016 2000,2004,2008,2012,2016 2000,2004,2008,2012,2016 ( 4 + 5 ) % 7 = 2 (4+5)\%7=2 (4+5)%7=2。也就是说 1999 1999 1999
10 10 10 1 1 1 日多加两天是星期日,那么 1999 1999 1999 10 10 10 1 1 1 日是星期五

  1. 甲、乙、丙三位同学选修课程,从 4 4 4 门课程中,甲选修 2 2 2 门,乙、丙各选修 3 3 3 门,则不同的选修方案共有( )种。

【解析】乘法原理:

  • ①甲的方案数: C 4 2 = 6 C_4^2=6 C42=6
  • ②乙的方案数: C 4 3 = 4 C_4^3=4 C43=4
  • ③丙的方案数: C 4 3 = 4 C_4^3=4 C43=4

乘法原理总的方案数为: 6 × 4 × 4 = 96 6\times4\times4=96 6×4×4=96

  1. G G G 是有 n n n 个结点、 m m m 条边( n ≤ m n \le m nm)的连接图,必须删去 G G G 的( )条边,才能使得 G G G 变成一棵树。

【解析】 n n n个结点的树一定有 n − 1 n - 1 n1条边,必须从图中删除 m − n + 1 m - n + 1 mn+1条边。

  1. 表达式 a*(b+c)*d 的后缀形式是( )。

【解析】套括号提取运算符。 ((a×(b+c))×d),将运算符提取到所在括号的右边:a b c + × d ×

  1. 若串 S="copyright",其子串的个数是( )。

【解析】

  • 长度为0的子串=1
  • 长度为1的子串=9

一共有=1 + 9 + 8 + … + 1 = 46

  1. 十进制小数 13.375 13.375 13.375 对应的二进制数是( )。

【解析】整数部分除2取余逆序连接,小数部分乘2取整顺序连接

  1. A A A B B B 是两个长为 n n n 的有序数组,现在需要将 A A A B B B 合并成一个排好序的数组,任何以元素比较作为基本运算的归并算法在最坏情况下至少要做( )次比较。

【解析】在最坏情况下, B B B中除了最后一个数,每个数都会比较2次,一共 2n - 2次,最后一个数只比较1次,所以结果为2n - 1

  1. 一家四口人,至少两个人生日属于同一月份的概率是( )。(假定每个人生日属于每个月份的概率相同且不同人之间相互独立)。

【解析】补集思想 至少两个人生日属于同一月份的概率 = 1 - 所有人的生日都是不同月份的概率。 所有人的生日都是不同月份的概率 = P 12 4 1 2 4 = 55 96 \frac{P_{12}^4}{12^4}= \frac{55}{96} 124P124=9655
答案: 1 − 55 96 = 41 96 1-\frac{55}{96}=\frac{41}{96} 19655=9641

问题求解

  1. 一个人站在坐标 ( 0 , 0 ) (0,0) (00)处,面朝 x x x 轴正方向。第一轮,他向前走 1 1 1 单位距离,然后右转;第二轮,他向前走 2 2 2 单位距离,然后右转;第三轮,他向前走 3 3 3 单位距离,然后右转……他一直这么走下去。请问第 2017 2017 2017 轮后,他的坐标是:(___ , ___)。
    在这里插入图片描述

【解析】模拟找规律。

  • 第①轮: x = 1 , y = 0 x=1, y=0 x=1,y=0
  • 第②轮: x = 1 , y = − 2 x=1, y=-2 x=1,y=2
  • 第③轮: x = − 2 , y = − 2 x=-2, y=-2 x=2,y=2
  • 第④轮: x = − 2 , > y = 2 x=-2,> y=2 x=2,>y=2
  • 第⑤轮: x = 3 , y = 2 x=3, y=2 x=3,y=2
  • 第⑥轮: x = 3 , y = − 4 x=3, y=-4 x=3,y=4
  • 第⑦轮: x = − 4 , y = − 4 x=-4, y=-4 x=4,y=4
  • 第⑧轮: x = − 4 , y = 4 x=-4, y=4 x=4,y=4
  • 第⑨轮: x = 5 , y = 4 x=5, y=4 x=5,y=4

每4轮转一圈,第2017轮刚好是从第二象限水平向右走到第一象限,此时:
x = ⌊ 2017 2 ⌋ + 1 x= \lfloor \frac{2017}{2}\rfloor + 1 x=22017+1 y = ⌊ 2017 2 ⌋ y= \lfloor \frac{2017}{2}\rfloor y=22017

  1. 如下图所示,共有 13 13 13个格子。对任何一个格子进行一次操作,会使得它自己以及与它上下左右相邻的格子中的数字改变(由 1 1 1 0 0 0,或由 $0 变 1 1 1)。现在要使得所有的格子中的数字都变为 0 0 0,至少需要_____次操作。
    在这里插入图片描述

【解析】按照红绿蓝三个格子的顺序进行操作即可。

阅读程序写结果

#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", g(m, n, 0));
    return  0;
}

输入:7 3

【解析】手动模拟递归调用。

在这里插入图片描述
答案:8
2.

#include <iostream>
#include <string>
using namespace std;
int main()
{
    string ch;
    int a[200];
    int b[200];
    int n, i, t, res;
    cin >> ch;
    n = ch.length();
    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;
    }
    cout << res << endl;
    return 0;
}

输入: 1001101011001101101011110001 1001101011001101101011110001 1001101011001101101011110001

【解析】手动模拟。
a[]记录输入的01序列。b[i]表示序列前i个数中1的个数。
变量t记录从序列从后向前(从ni)中0的个数。
变量res为序列前i-1个数中1的个数和从in中0的个数之和的最小值。
1001101011001101101011110001
答案为:11

#include <iostream>
using namespace std;
int main()
{
    int n, m;
    cin >> n >> m;
    int x = 1;
    int y = 1;
    int dx = 1;
    int dy = 1;
    int cnt = 0;
    while(cnt != 2) {
        cnt = 0;
        x = x + dx;
        y = y + dy;
        if(x == 1 || x == n) {
            ++cnt;
            dx = -dx;
        }
        if(y == 1 || y == m) {
            ++cnt;
            dy = -dy;
        }
    }
    cout << x << " " << y << endl;
    return  0 ;
}

【解析】手动模拟,找规律

输入:4 3

n = 4, m = 3, dx = 1, dy = 1, x = 1, y = 1
x = 2, y = 2
x = 3, y = 3, dy = -1
x = 4, y = 2, dx = -1
x = 3, y = 1, dy = 1
x = 2, y = 2
x = 1, y = 3, dx = 1, dy = -1, cnt = 2

答案:1 3
输入:2017 1014

n = 2017, m = 1014, dx = 1, dy = 1, x = 1, y = 1
x = 2, y = 2

x = 1014, y = 1014, dy = -1
x = 1015, y = 1013

x = 2017, y = 1, dx = -1, dy = 1, cnt = 2
答案:2017 1

完善程序

(切割绳子)有 nn 条绳子,每条绳子的长度已知且均为正整数。绳子可以以任意正整数长度切割,但不可以连接。现在要从这些绳子中切割出m条长度相同的绳段,求绳段的最大长度是多少。
输入:第一行是一个不超过 100 100 100的正整数 n n n,第二行是 n n n 个不超过 1 0 6 10^6 106 的正整数,表示每条绳子的长度,第三行是一个不超过 1 0 8 10^8 108 的正整数 m m m
输出 :绳段的最大长度,若无法切割,输出 Failed。

#include <iostream>
using namespace std;
int n, m, i, lbound, ubound, mid, count;
int  len[100]; //绳子长度
int main()
{
    cin >> n;
    count = 0;
    for (i = 0; i < n; i++) {
        cin >> len[i];
        ①;
    }
    cin >> m;
    if (②) {
        cout << "Failed" << endl;
        return 0;
    }
    lbound = 1 ;
    ubound = 1000000 ;
    while (③) {
        mid = ④;
        count =0 ;
        for (i = 0; i < n; i++ )
            ⑤;
        if (count < m)
            ubound = mid - 1 ;
        else
            lbound = mid ;
    }
    cout << lbound << endl;
    return 0;
}

【解析】二分搜索求切割出m条长度相同的绳段的最大长度。
空①,累加所有绳子的长度,答案:count+=len[i]
空②,如果绳子的总长度<m,那么不可能分割。答案:count<m
空③,二分搜索条件,lbound<rbound
空④,取中间值,注意,所有count>=m的情况都可行,要左边区间的最大值,适用二分搜索模板2,答案:(lbound+rbound+1)/2
空⑤,累加分割的绳子数量,答案:count+=len[i]/m

猜你喜欢

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