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

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

    1. 平方十位数

    由0~9这10个数字不重复、不遗漏,可以组成很多10位数字。
    这其中也有很多恰好是平方数(是某个数的平方)。

    比如:1026753849,就是其中最小的一个平方数。

    请你找出其中最大的一个平方数是多少?

    注意:你需要提交的是一个10位数字,不要填写任何多余内容。

    答案:9814072356

    暴力找即可

    ll n = 9876543210;
    int vis[10] = {0};
    void solve() {
    	while (n--) {
    		ll x = (int)sqrt(n);
    		if (x * x == n) {
    			memset(vis, 0, sizeof(vis));
    			ll t = n;
    			while (t > 0)vis[t % 10]++, t /= 10;
    			bool f = true;
    			for (int i = 0; i <= 9 and f; ++i)
    				if (vis[i] != 1)f = false;
    			if (f) {cout << n << "
    "; return;}
    		}
    	}
    }
    

    2.生命游戏

    康威生命游戏是英国数学家约翰·何顿·康威在1970年发明的细胞自动机。
    这个游戏在一个无限大的2D网格上进行。

    初始时,每个小方格中居住着一个活着或死了的细胞。
    下一时刻每个细胞的状态都由它周围八个格子的细胞状态决定。

    具体来说:

    1. 当前细胞为存活状态时,当周围低于2个(不包含2个)存活细胞时, 该细胞变成死亡状态。(模拟生命数量稀少)
    2. 当前细胞为存活状态时,当周围有2个或3个存活细胞时, 该细胞保持原样。
    3. 当前细胞为存活状态时,当周围有3个以上的存活细胞时,该细胞变成死亡状态。(模拟生命数量过多)
    4. 当前细胞为死亡状态时,当周围有3个存活细胞时,该细胞变成存活状态。 (模拟繁殖)

    当前代所有细胞同时被以上规则处理后, 可以得到下一代细胞图。按规则继续处理这一代的细胞图,可以得到再下一代的细胞图,周而复始。

    例如假设初始是:(X代表活细胞,.代表死细胞)

    .....
    .....
    .XXX.
    .....
    

    下一代会变为:

    .....
    ..X..
    ..X..
    ..X..
    .....
    

    康威生命游戏中会出现一些有趣的模式。例如稳定不变的模式:

    ....
    .XX.
    .XX.
    ....
    

    还有会循环的模式:

    ......      ......       ......
    .XX...      .XX...       .XX...
    .XX...      .X....       .XX...
    ...XX.   -> ....X.  ->   ...XX.
    ...XX.      ...XX.       ...XX.
    ......      ......       ......
    

    本题中我们要讨论的是一个非常特殊的模式,被称作"Gosper glider gun":

    ......................................
    .........................X............
    .......................X.X............
    .............XX......XX............XX.
    ............X...X....XX............XX.
    .XX........X.....X...XX...............
    .XX........X...X.XX....X.X............
    ...........X.....X.......X............
    ............X...X.....................
    .............XX.......................
    ......................................
    

    假设以上初始状态是第0代,请问第1000000000(十亿)代一共有多少活着的细胞?

    注意:我们假定细胞机在无限的2D网格上推演,并非只有题目中画出的那点空间。
    当然,对于遥远的位置,其初始状态一概为死细胞。

    注意:需要提交的是一个整数,不要填写多余内容。

    答案: 166666713

    ll x = 1e9;
    void solve() {
    	// cout << "lll " << x / 10 << "
    ";
    	ll sum = (x / 30) * 5;
    	x %= 30;
    	// cout << "x= " << x << "
    ";
    	int s[30] = {3, 4, 5, 3, -7, 7, -3, 13, -19, 6, 2, 4, 1, 1, -14, 2, 3, 6, 1, 0, 0, -5, 11, -17, 7, -3, 0, 3, -2, -7};
    	int cnt = 0;
    	for (int i = 0; i < x; ++i)cnt += s[i];
    	// cout << cnt << " " << "jjj" << '
    ';
    	sum += cnt + 36;//36为初始细胞数
    	cout << sum;
    }
    

    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");// 100
        printf("%d
    ", x);
        return 0;
    }
    

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

    答案:f3(s, p0, p)

    仔细阅读代码即可

    4.填字母游戏

    小明经常玩 LOL 游戏上瘾,一次他想挑战K大师,不料K大师说:
    “我们先来玩个空格填字母的游戏,要是你不能赢我,就再别玩LOL了”。

    K大师在纸上画了一行n个格子,要小明和他交替往其中填入字母。

    并且:

    1. 轮到某人填的时候,只能在某个空格中填入L或O
    2. 谁先让字母组成了“LOL”的字样,谁获胜。
    3. 如果所有格子都填满了,仍无法组成LOL,则平局。

    小明试验了几次都输了,他很惭愧,希望你能用计算机帮他解开这个谜。

    本题的输入格式为:
    第一行,数字n(n<10),表示下面有n个初始局面。
    接下来,n行,每行一个串(长度<20),表示开始的局面。
    比如:“******”, 表示有6个空格。
    “L****”, 表示左边是一个字母L,它的右边是4个空格。

    要求输出n个数字,表示对每个局面,如果小明先填,当K大师总是用最强着法的时候,小明的最好结果。
    1 表示能赢
    -1 表示必输
    0 表示可以逼平

    例如,
    输入:

    4
    ***
    L**L
    L**L***L
    L*****L
    

    则程序应该输出:

    0
    -1
    1
    1
    

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

    【思路】

    搜索加个记忆化,注意这里不要用 map ,map 会大大增加复杂度(那么答案只有一个了),这里用字符串 hash,我用特殊方法得知输入最长的字符串长度是 20,如果全是 * 的话一共有 3^20 种状态,想必怎么装都装不下(丧心病狂,大概也不会空那么多位置的吧),这里用 3 进制来存放每一个状态即可(已经是压缩到极限了,即每个数对应一个状态),数组开爆就过了,太小的话有些状态会引起冲突,导致错误,大概就是这样。

    constexpr auto inf = 0x3f3f3f3f;
    using ll = long long;
    const int N = 1e7 + 10;
    string ovo;
    int M[N], Map[233];
    int Hash() {
        unsigned long long v = 0;
        for (int pos = 0; ovo[pos]; pos++) v = v * 3 + Map[ovo[pos]];
        return v % 9817117;
    }
    /* 993217 492253 9817117 */
    int Fun() {
        int u = Hash();
        if (M[u] != inf) return M[u];
        if (ovo.find("LOL") != string::npos) return M[u] = -1;
        if (ovo.find("*") == string::npos) return M[u] = 0;
        int res = -1;
        for (int pos = 0; ovo[pos] && res != 1; pos++)
            if (ovo[pos] == '*') {
                ovo[pos] = 'L', res = max(res, -Fun());
                if (res != 1)
                    ovo[pos] = 'O', res = max(res, -Fun());
                ovo[pos] = '*';
            }
        return M[u] = res;
    }
    void solve() {
        Map['*'] = 0, Map['L'] = 1, Map['O'] = 2;
        int n, bit = sizeof(M);
        cin >> n;
        while (n--) {
            memset(M, inf, sizeof(M));
            cin >> ovo, cout << Fun() << "
    ";
        }
    }
    

    map 的记忆化( T 掉的 40 分):

    string ovo; map<string, int> M;
    int F() {
        if (M.find(ovo) != M.end()) return M[ovo];
        if (ovo.find("LOL") != string::npos) return -1;
        if (ovo.find("*") == string::npos) return  0;
        int res = -1;
        for (int pos = 0; ovo[pos]; pos++)
            if (ovo[pos] == '*') {
                ovo[pos] = 'L'; res = max(res, -F());
                ovo[pos] = 'O'; res = max(res, -F());
                ovo[pos] = '*';
            }
        return M[ovo] = res;
    }
    
    int main() {
        int N; cin >> N;
        while (N--) {
            M.clear(), cin >> ovo, cout << F() << endl;
        }
    }
    

    5.区间移位

    数轴上有n个闭区间:D1,...,Dn。
    其中区间Di用一对整数[ai, bi]来描述,满足ai < bi。
    已知这些区间的长度之和至少有10000。
    所以,通过适当的移动这些区间,你总可以使得他们的“并”覆盖[0, 10000]——也就是说[0, 10000]这个区间内的每一个点都落于至少一个区间内。
    你希望找一个移动方法,使得位移差最大的那个区间的位移量最小。

    具体来说,假设你将Di移动到[ai+ci, bi+ci]这个位置。你希望使得maxi{|ci|} 最小。

    【输入格式】
    输入的第一行包含一个整数n,表示区间的数量。
    接下来有n行,每行2个整数ai, bi,以一个空格分开,表示区间[ai, bi]。
    保证区间的长度之和至少是10000。

    【输出格式】
    输出一个数字,表示答案。如果答案是整数,只输出整数部分。如果答案不是整数,输出时四舍五入保留一位小数。

    【样例输入】

    2
    10 5010
    4980 9980
    

    【样例输出】

    20
    

    【样例说明】
    第一个区间往左移动10;第二个区间往右移动20。

    【样例输入】

    4
    0 4000
    3000 5000
    5001 8000
    7000 10000
    

    【样例输出】

    0.5
    

    【样例说明】
    第2个区间往右移0.5;第3个区间往左移0.5即可。

    【数据规模与约定】
    对于30%的评测用例,(1 <= n <= 10)
    对于100%的评测用例,(1 <= n <= 10000,0 <= a_i < b_i <= 10000)

    6.数组操作

    给出一个长度为 n 的数组 {A},由 1 到 n 标号 , 你需要维护 m 个操作。
    操作分为三种,输入格式为:

    1 L R d,将数组中下标 L 到 R 的位置都加上 d,即对于 L<=i<=R,执行A[i]=A[i]+d。

    2 L1 R1 L2 R2,将数组中下标为 L1 到 R1 的位置,赋值成 L2 到 R2 的值,保证 R1-L1=R2-L2。
    换句话说先对 0<=i<=R2-L2 执行 B[i]=A[L2+i],再对 0<=i<=R1-L1 执行 A[L1+i]=B[i],其中 {B} 为一个临时数组。

    3 L R,求数组中下标 L 到 R 的位置的和,即求出 $∑_(i=L到R) A_i $。

    输入格式:
    从标准输入读入数据。
    第一行一个整数 Case,表示测试点编号,其中 Case=0 表示该点为样例。
    第二行包含两个整数 n,m。保证 (1<=n,m<=10^5)
    第三行包含 n 个整数 (A_i),表示这个数组的初值。保证 (0<=A_i<=10^5)
    接下来 m 每行描述一个操作,格式如问题描述所示。
    对于操作中提到每个数,满足 0<=d<=10^5,1<=L<=R<=n,1<=L1<=R1<=n,1<=L2<=R2<=n,R1-L1=R2-L2​。

    输出格式:
    输出到标准输出。
    对于每次 3 操作输出一行一个数,表示求和的结果。

    样例输入:

    0
    5 6
    1 2 3 4 5
    2 1 3 3 5
    3 3 5
    1 2 4 2
    3 3 5
    2 1 3 3 5
    3 1 5
    

    样例输出:

    14
    18
    29
    
    ----------------------------
    测试点	  n,m	       其他约束
    ----------------------------
    1,2      <=10^3	       无
    3,4      <=10^5	       没有2操作
    5,6,7     <=10^5       n 为偶数,且所有2操作满足 L1=1,R1=n/2  ,L2=n/2+1,R2=n
    8,9,10	  <=10^5       无
    

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

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

  • 相关阅读:
    【浏览器】谷歌浏览器快捷键
    【问题】html页面不能自动更新,重启项目也不行。package时可以。
    Hibernate与mybatis的区别
    ssh的执行流畅
    ssm执行流程
    struts的上传下载
    HTML列表
    什么是HTML,HTML的简介,HTML结构
    hadoop hdfs 分布式存储
    面向对象的七大原则
  • 原文地址:https://www.cnblogs.com/RioTian/p/14803955.html
Copyright © 2011-2022 走看看