zoukankan      html  css  js  c++  java
  • 2017年第八届 蓝桥杯C组 C/C++决赛题解

    蓝桥杯历年国赛真题汇总:Here

    1.哥德巴赫分解

    哥德巴赫猜想认为:不小于4的偶数都可以表示为两个素数的和。

    你不需要去证明这个定理,但可以通过计算机对有限数量的偶数进行分解,验证是否可行。

    实际上,一般一个偶数会有多种不同的分解方案,我们关心包含较小素数的那个方案。
    对于给定数值范围,我们想知道这些包含较小素数方案中最大的素数是多少。

    比如,100以内,这个数是19,它由98的分解贡献。

    你需要求的是10000以内,这个数是多少?

    答案:173

    const int N = 10000;
    vector<int>prime;
    bool vis[10010];
    int ans;
    void check(int n) {
        for (int i = 0; i < prime.size(); ++i) {
            int r = n - prime[i];
            if (vis[r]) {
                ans = max(ans, prime[i]);
                return ;
            }
        }
    }
    void solve() {
        memset(vis, true, sizeof(vis));
        for (int i = 2; i < N; ++i)
            if (vis[i])for (int j = i + i; j < N; j += i)vis[j] = false;
        for (int i = 2; i < N; ++i)if (vis[i])prime.push_back(i);
        for (int i = 4; i < 10000; i += 2)check(i);
        cout << ans << "
    ";
    }
    

    2.数字划分

    w星球的长老交给小明一个任务:
    1,2,3...16 这16个数字分为两组。
    要求:
    这两组数字的和相同,
    并且,两组数字的平方和也相同,
    并且,两组数字的立方和也相同。

    请你利用计算机的强大搜索能力解决这个问题。
    并提交1所在的那个分组的所有数字。

    这些数字要从小到大排列,两个数字间用一个空格分开。
    即类似:1 4 5 8 ... 这样的答案。

    注意,只提交这一组数字,不要填写任何多余的内容。


    笨笨有话说:
    只要一个组的成员确定了,另一个组的成员也就确定了。枚举一个组的成员就可以了。
    凭直觉,两个组的成员数目不会差太多吧。
    歪歪有话说:
    既然求 1 所在的那个组,那只要枚举剩余的成员就可以了。
    貌似都是8个成员的可能性很大啊。

    答案:1 4 6 7 10 11 13 16

    爆搜

    bool vis[17];
    void dfs(int pos, int cnt) {
        if (cnt == 8) {
            int sum1 = 0, sum2 = 0, sum11 = 0, sum22 = 0;
            for (int i = 1; i <= 16; ++i) {
                if (!vis[i])sum1 += i * i, sum2 += i * i * i;
                else sum11 += i * i, sum22 += i * i * i;
            }
            if (sum1 == sum11 and sum2 == sum22) {
                for (int i = 1; i <= 16; ++i)if (!vis[i]) cout << i << " " ;
                cout << "
    "; return; // 找到一组就直接推出即可
            }
            return ;
        }
        for (int i = pos + 1; i <= 16; ++i) {
            if (!vis[i])continue;
            vis[i] = false;
            dfs(i, cnt + 1);
            vis[i] = true;
        }
    }
    

    3.表达式计算

    虽然我们学了许久的程序设计,但对于简单的四则混合运算式,如果让我们完全白手起家地编程来解析,还是有点棘手。

    这里,我们简化一下问题,假设只有加法和乘法,并且没有括号来改变优先级。
    再假设参加运算的都是正整数。

    在这么多的限制条件下,表达式的解析似乎简单了许多。
    下面的代码解决了这个问题。请仔细阅读源码,并填写划线部分缺少的代码。

    #include <stdio.h>
    
    int f3(const char* s, int begin, int end) {
        int sum = 0;
        int i;
        for (i = begin; i < end; i++) {
            if (s[i] == ' ') continue;
            sum = sum * 10 + (s[i] - '0');
        }
        return sum;
    }
    
    int f2(const char* s, int begin, int end) {
        int p = begin;
        int pro = 1;
        while (1) {
            int p0 = p;
            while (p != end && s[p] != '*') p++;
            pro *= _______________________________;  //填空
            if (p == end) break;
            p++;
        }
        printf("f2: pro=%d
    ", pro);
        return pro;
    }
    
    int f(const char* s) {
        int p = 0;
        int sum = 0;
        while (1) {
            int p0 = p;
            while (s[p] != 0 && s[p] != '+') p++;
            sum += f2(s, p0, p);
            if (s[p] == 0) break;
            p++;
        }
        return sum;
    }
    
    int main() {
        int x = f("12+18+5*4*3+10");
        printf("%d
    ", x); // 100
        return 0;
    }
    

    注意:只填写划线处缺少的内容,不要填写已有的代码或符号,也不要填写任何解释说明文字等。

    答案:f3(s, p0, p)

    仔细阅读代码即可

    4.小数第n位

    我们知道,整数做除法时,有时得到有限小数,有时得到无限循环小数。
    如果我们把有限小数的末尾加上无限多个0,它们就有了统一的形式。

    本题的任务是:在上面的约定下,求整数除法小数点后的第n位开始的3位数。

    输入:
    一行三个整数:a b n,用空格分开。a是被除数,b是除数,n是所求的小数后位置(0<a,b,n<1000000000)
    输出:
    一行3位数字,表示:a除以b,小数后第n位开始的3位数字。

    比如:
    输入:

    1 8 1
    

    程序应该输出:

    125
    

    再比如:
    输入:

    1 8 3
    

    程序应该输出:

    500
    

    再比如:
    输入:

    282866 999000 6
    

    程序应该输出:

    914
    

    提交时,注意选择所期望的编译器类型。


    笨笨有话说:
    这个除法小学就会算啊,模拟手算除法的过程就可以了吧。
    只是数有点大啊....
    管它呢,能算多远算多远....

    歪歪有话说:
    如果我能确定循环节从哪里开始到哪里结束,再大的数不过就是与它取模的余数等价啊

    【思路】

    模拟除法。
        13 / 7 = 1.85714285...
         
    这里求小数部分,所有取模忽略掉整数部分
    13 / 7 -> 6 / 7
     
    第一位:(小数点后第几位,以下同)6 * 10 / 7 = 8;
    得到第一位后的余数:6 * 10 % 7 = 4
     
    那么第二位:4 * 10 / 7 = 5
    得到第二位后的余数:4 * 10 % 7 = 5
     
    第三位:5 * 10 / 7 = 7
     
    依此类推
    
    void solve() {
        ll a, b, n;
        cin >> a >> b >> n;
        a %= b;
        while (n > 10) {
            a *= 1E10; a %= b; n -= 10;
        }
        for (int i = 0; i < n + 2; ++i) {
            a *= 10;
            if (i >= n - 1)cout << a / b;
            a %= b;
        }
    }
    

    5.分考场

    n个人参加某项特殊考试。
    为了公平,要求任何两个认识的人不能分在同一个考场。
    求最少需要分几个考场才能满足条件。

    输入格式:
    第一行,一个整数n(1<n<100),表示参加考试的人数。
    第二行,一个整数m,表示接下来有m行数据
    以下m行每行的格式为:两个整数a,b,用空格分开 (1<=a,b<=n) 表示第a个人与第b个人认识(编号从1开始)。

    输出格式:
    一行一个整数,表示最少分几个考场。

    例如:
    输入:

    5
    8
    1 2
    1 3
    1 4
    2 3
    2 4
    2 5
    3 4
    4 5
    

    程序应该输出:

    4
    

    再比如:
    输入:

    5
    10
    1 2
    1 3
    1 4
    1 5
    2 3
    2 4
    2 5
    3 4
    3 5
    4 5
    

    则程序应该输出:

    5
    

    资源约定:
    峰值内存消耗 < 256M
    CPU消耗 < 1000ms

    【思路】

    一开始以为是并查集之类的连通图大小的问题,写了一发结果只通过 30% 的数据,重新审题发现其实就是图的着色问题:给定顶点数和边,求至少需要多少种颜色对图进行涂色能是相邻顶点颜色不同。

    const int N = 110, inf = 0x3f3f3f3f;
    int e[N][N];
    int vis[N][N]; // vis[i][j] = t表示第i个考场里面第j个人是t
    int cnt[N]; // 记录每个考场种的学生数量(对应的vis)
    int ans = inf, n, m;
    void dfs(int id, int num) {// id表示第id个学生,num表示当前考场编号
    	if (num >= ans)return;
    	if (id > n) {  // 学生已经安排完了
    		ans = min(ans, num);// 更新当前最优解(不要用min可能超时)
    		return;
    	}
    	for (int i = 1; i <= num; ++i) {// 先看之前分配为的考场里面能不能进去
    		int rnd = 0;// 表示id学生与第i个考场里面的人不认识的数量
    		for (int j = 1; j <= cnt[i]; ++j) // cnt[i]表示第i个考场里面的人数
    			if (e[id][vis[i][j]] == 0)rnd ++;
    		if (rnd == cnt[i]) { // 如果都不认识
    			vis[i][++cnt[i]] = id;
    			dfs(id + 1, num);
    			cnt[i]--;// 回溯
    		}
    	}
    	// 现有考场都不行,就要增加考场
    	vis[num + 1][++cnt[num + 1]] = id;
    	dfs(id + 1, num + 1);
    	--cnt[num + 1]; // 回溯
    }
    void solve() {
    	cin >> n >> m;
    	while (m--) {
    		int u, v;
    		cin >> u >> v;
    		e[u][v] = e[v][u] = 1;
    	}
    	dfs(1, 0);
    	cout << ans << "
    ";
    }
    

    6.合根植物

    w星球的一个种植园,被分成 m * n 个小格子(东西方向m行,南北方向n列)。每个格子里种了一株合根植物。
    这种植物有个特点,它的根可能会沿着南北或东西方向伸展,从而与另一个格子的植物合成为一体。

    如果我们告诉你哪些小格子间出现了连根现象,你能说出这个园中一共有多少株合根植物吗?

    输入格式:
    第一行,两个整数m,n,用空格分开,表示格子的行数、列数(1<m,n<1000)。
    接下来一行,一个整数k,表示下面还有k行数据(0<k<100000)
    接下来k行,第行两个整数a,b,表示编号为a的小格子和编号为b的小格子合根了。

    格子的编号一行一行,从上到下,从左到右编号。
    比如:5 * 4 的小格子,编号:

    1  2  3  4
    5  6  7  8
    9  10 11 12
    13 14 15 16
    17 18 19 20
    

    样例输入:

    5 4
    16
    2 3
    1 5
    5 9
    4 8
    7 8
    9 10
    10 11
    11 12
    10 14
    12 16
    14 18
    17 18
    15 19
    19 20
    9 13
    13 17
    

    样例输出:

    5
    

    其合根情况参考图[p1.png]

    资源约定:
    峰值内存消耗 < 256M
    CPU消耗 < 2000ms

    待补

    The desire of his soul is the prophecy of his fate
    你灵魂的欲望,是你命运的先知。

  • 相关阅读:
    896. Monotonic Array单调数组
    865. Smallest Subtree with all the Deepest Nodes 有最深节点的最小子树
    489. Robot Room Cleaner扫地机器人
    JavaFX
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
  • 原文地址:https://www.cnblogs.com/RioTian/p/14803979.html
Copyright © 2011-2022 走看看