2014 【第五届蓝桥杯省赛】 C/C++A组

目录

第一题:猜年龄

第二题:切面条

第三题:神奇算式

第四题:史丰收速算 

第五题:锦标赛

 第六题:扑克序列

 第七题:蚂蚁感冒


第一题:猜年龄

    小明带两个妹妹参加元宵灯会。别人问她们多大了,她们调皮地说:“我们俩的年龄之积是年龄之和的6倍”。小明又补充说:“她们可不是双胞胎,年龄差肯定也不超过8岁啊。”

    请你写出:小明的较小的妹妹的年龄。

//非暴力,不合作。我赌她们不超过30岁
#include <iostream>
#include <cstring>
using namespace std;

int main()
{
    while (1)
    {
        int m = rand() % 30;
        int n = rand() % 30;
        if (m - n <= 8 && m != n)
        {
            if (m * n == 6 * (m + n))
            {
                cout << n;
                break;
            }
        }
    }
    system("pause");
    return 0;
}
/*
答案:10
*/

第二题:切面条

    一根高筋拉面,中间切一刀,可以得到2根面条。

    如果先对折1次,中间切一刀,可以得到3根面条。

    如果连续对折2次,中间切一刀,可以得到5根面条。

    那么,连续对折10次,中间切一刀,会得到多少面条呢?

 

答案是个整数,请通过浏览器提交答案。不要填写任何多余的内容。

//找规律
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;

int main()
{
    int k  = 2;
    for (int i = 1; i <= 10; i++)
    {
        k += pow(2,i-1);
    }
    cout << k;
    system("pause");
    return 0;
}
/*
答案:1025
*/

第三题:神奇算式

由4个不同的数字,组成的一个乘法算式,它们的乘积仍然由这4个数字组成。

比如:

210 x 6 = 1260

8 x 473 = 3784

27 x 81 = 2187

    都符合要求。

    如果满足乘法交换律的算式算作同一种情况,那么,包含上边已列出的3种情况,一共有多少种满足要求的算式。

    请填写该数字,通过浏览器提交答案,不要填写多余内容(例如:列出所有算式)。

//慢是慢了点,但谁让他是填空题呢。。。
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <set>
using namespace std;

int flag[1000][1000];
int main()
{
    int count = 0;
    for (int i = 1; i < 1000; i++)
    {
        for (int j = 1; j < 1000; j++)
        {
            if (flag[i][j] == 1)
                continue;

            int k = i * j;

            string s1 = to_string(k);

            string s2 = to_string(i) + to_string(j);

            int f = 1;
            for (int p = 0; p < s1.size(); p++)
            {
                if (s1.find(s1[p], p + 1) != string::npos)
                {
                    f = 0;
                    break;
                }
            }

            if (s1.size() != s2.size() || s1.size() != 4 || f == 0)
                continue;

            sort(s1.begin(), s1.end());
            sort(s2.begin(), s2.end());

            if (s1 == s2)
            {
                flag[i][j] = 1;
                flag[j][i] = 1;
                cout << i << " * " << j << " = " << k << endl;
                count++;
            }
        }
    }
    cout << count << endl;
    system("pause");
    return 0;
}
/*
答案:12
*/

第四题:史丰收速算 

    史丰收速算法的革命性贡献是:从高位算起,预测进位。不需要九九表,彻底颠覆了传统手算!

    速算的核心基础是:1位数乘以多位数的乘法。

    其中,乘以7是最复杂的,就以它为例。

    因为,1/7 是个循环小数:0.142857...,如果多位数超过 142857...,就要进1

    同理,2/7, 3/7, ... 6/7 也都是类似的循环小数,多位数超过 n/7,就要进n

    下面的程序模拟了史丰收速算法中乘以7的运算过程。

    乘以 7 的个位规律是:偶数乘以2,奇数乘以2再加5,都只取个位。

    乘以 7 的进位规律是:

       满 142857... 进1,

       满 285714... 进2,

       满 428571... 进3,

       满 571428... 进4,

       满 714285... 进5,

       满 857142... 进6

    请分析程序流程,填写划线部分缺少的代码。

//计算个位
int ge_wei(int a)
{
    if (a % 2 == 0)
        return (a * 2) % 10;
    else
        return (a * 2 + 5) % 10;
}

//计算进位
int jin_wei(char *p)
{
    char *level[] = {
        "142857",
        "285714",
        "428571",
        "571428",
        "714285",
        "857142"};

    char buf[7];
    buf[6] = '\0';
    strncpy(buf, p, 6);

    int i;
    for (i = 5; i >= 0; i--)
    {
        int r = strcmp(level[i], buf);
        if (r < 0)
            return i + 1;
        while (r == 0)
        {
            p += 6;
            strncpy(buf, p, 6);
            r = strcmp(level[i], buf);
            if (r < 0)
                return i + 1;
            ______________________________; //填空
        }
    }

    return 0;
}

//多位数乘以7
void f(char *s)
{
    int head = jin_wei(s);
    if (head > 0)
        printf("%d", head);

    char *p = s;
    while (*p)
    {
        int a = (*p - '0');
        int x = (ge_wei(a) + jin_wei(p + 1)) % 10;
        printf("%d", x);
        p++;
    }

    printf("\n");
}

int main()
{
    f("428571428571");
    f("34553834937543");
    return 0;
}

注意:通过浏览器提交答案。只填写缺少的内容,不要填写任何多余的内容(例如:说明性文字) 

if (r > 0)
     return i;

第五题:锦标赛

   如果要在n个数据中挑选出第一大和第二大的数据(要求输出数据所在位置和值),使用什么方法比较的次数最少?我们可以从体育锦标赛中受到启发。

   如图【1.png】所示,8个选手的锦标赛,先两两捉对比拼,淘汰一半。优胜者再两两比拼...直到决出第一名。

   第一名输出后,只要对黄色标示的位置重新比赛即可。

   下面的代码实现了这个算法(假设数据中没有相同值)。

   代码中需要用一个数组来表示图中的树(注意,这是个满二叉树,不足需要补齐)。它不是存储数据本身,而是存储了数据的下标。  

    第一个数据输出后,它所在的位置被标识为-1

//重新决出k号位置,v为已输出值
void pk(int *a, int *b, int n, int k, int v)
{
    int k1 = k * 2 + 1;
    int k2 = k1 + 1;

    if (k1 >= n || k2 >= n)
    {
        b[k] = -1;
        return;
    }

    if (b[k1] == v)
        pk(a, b, n, k1, v);
    else
        pk(a, b, n, k2, v);

    //重新比较
    if (b[k1] < 0)
    {
        if (b[k2] >= 0)
            b[k] = b[k2];
        else
            b[k] = -1;
        return;
    }

    if (b[k2] < 0)
    {
        if (b[k1] >= 0)
            b[k] = b[k1];
        else
            b[k] = -1;
        return;
    }

    if (______________________) //填空
        b[k] = b[k1];
    else
        b[k] = b[k2];
}

//对a中数据,输出最大,次大元素位置和值
void f(int *a, int len)
{
    int n = 1;
    while (n < len)
        n *= 2;

    int *b = (int *)malloc(sizeof(int *) * (2 * n - 1));
    int i;
    for (i = 0; i < n; i++)
    {
        if (i < len)
            b[n - 1 + i] = i;
        else
            b[n - 1 + i] = -1;
    }

    //从最后一个向前处理
    for (i = 2 * n - 1 - 1; i > 0; i -= 2)
    {
        if (b[i] < 0)
        {
            if (b[i - 1] >= 0)
                b[(i - 1) / 2] = b[i - 1];
            else
                b[(i - 1) / 2] = -1;
        }
        else
        {
            if (a[b[i]] > a[b[i - 1]])
                b[(i - 1) / 2] = b[i];
            else
                b[(i - 1) / 2] = b[i - 1];
        }
    }

    //输出树根
    printf("%d : %d\n", b[0], a[b[0]]);

    //值等于根元素的需要重新pk
    pk(a, b, 2 * n - 1, 0, b[0]);

    //再次输出树根
    printf("%d : %d\n", b[0], a[b[0]]);

    free(b);
}

int main()
{
    int a[] = {54, 55, 18, 16, 122, 17, 30, 9, 58};
    f(a, 9);
}

请仔细分析流程,填写缺失的代码。

    通过浏览器提交答案,只填写缺失的代码,不要填写已有代码或其它说明语句等。

b[k1] > b[k2]

 第六题:扑克序列

    A A 2 2 3 3 4 4, 一共4对扑克牌。请你把它们排成一行。

    要求:两个A中间有1张牌,两个2之间有2张牌,两个3之间有3张牌,两个4之间有4张牌。

    请填写出所有符合要求的排列中,字典序最小的那个。

例如:22AA3344 比 A2A23344 字典序小。当然,它们都不是满足要求的答案。

 

请通过浏览器提交答案。“A”一定不要用小写字母a,也不要用“1”代替。字符间一定不要留空格。

#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <set>
using namespace std;

int main()
{
    string s("223344AA");
    do
    {
        int flag = true;
        for (int i = 1; i <= 4; i++)
        {
            char c = (i == 1) ? 'A' : i + 48;
            int pos1 = s.find_first_of(c);
            int pos2 = s.find_last_of(c);
            if (pos2 - pos1 != i + 1)
            {
                flag = false;
                break;
            }
        }
        if (flag)
        {
            cout << s << endl;
            break;
        }
    } while (next_permutation(s.begin(), s.end()));

    system("pause");
    return 0;
}
/*
2342A3A4
*/

 第七题:蚂蚁感冒

 

    长100厘米的细长直杆子上有n只蚂蚁。它们的头有的朝左,有的朝右。

    每只蚂蚁都只能沿着杆子向前爬,速度是1厘米/秒。

    当两只蚂蚁碰面时,它们会同时掉头往相反的方向爬行。

   这些蚂蚁中,有1只蚂蚁感冒了。并且在和其它蚂蚁碰面时,会把感冒传染给碰到的蚂蚁。

 

    请你计算,当所有蚂蚁都爬离杆子时,有多少只蚂蚁患上了感冒。

输入

第一行输入一个整数n  (1  <   n  <   50),  表示蚂蚁的总数。 

接着的一行是n个用空格分开的整数  Xi  (-100  <   Xi  <   100),  Xi的绝对值,表示蚂蚁离开杆子左边端点的距离。正值表示头朝右,负值表示头朝左,数据中不会出现0值,也不会出现两只蚂蚁占用同一位置。其中,第一个数  据代表的蚂蚁感冒了。

输出

要求输出1个整数,表示最后感冒蚂蚁的数目。 

样例输入

5
-10 8 -20 12 25

样例输出

3

 

 emm,规律就是:

被感染的蚂蚁 数量 等于 

第一只蚂蚁本身,

加 它左边往右走的蚂蚁数量  加 它右边往左走的蚂蚁数量。

红色 : 第一只蚂蚁 

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n, sick = 1;
    cin >> n;
    int *ant = new int[n];
    for (int i = 0; i < n; i++)
        cin >> ant[i];
    for (int i = 1; i < n; i++)
    {
        if (abs(ant[i]) < abs(ant[0]) && ant[i] > 0)
            sick++;
        if (abs(ant[i]) > abs(ant[0]) && ant[i] < 0)
            sick++;
    }
    cout << sick << endl;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值