2015年蓝桥杯省赛B组C/C++(试题+答案)

首先说,这次我是第二次参加蓝桥杯(大学里最后一次),可这次去连个三等都没拿到,有些心灰意冷,比上一次还差,

当时看到成绩出来的时候有些失落,但是跌倒了,再站起来继续跑就可以了。可能是状态不好吧,纯属自我安慰。

接下来我把今年的题目又重新做了一遍,写下了这篇博客,如果也有需要探讨答案的,希望可以有帮助。

第一题:

第1题:统计不含4的数字

题目大意

  统计10000至99999中,不包含4的数值个数。

解题分析: 

第一种解法:

数学方法,这种是在网上看到的一种解法:

  最高位除了0、4不能使用,其余8个数字(1,2,3,5,6,7,8,9)均能使用,剩下的四位(千位、百位、十位、个位)

可以使用除了4以外的所有数字,所以共有 8*9*9*9*9种解,

计算得答案为:52488。

第二种解法:

暴力搜索方法,这个数字的位数共有5位因此,可以设置a, b, c, d, e,分别代表这5位。

代码:

#include <iostream>

#include <cstdio>

using namespace std;

int main()

{

int a, b, c, d, e;

int count = 0;

for(a = 1; a <= 9; a++)

{

for(b = 0; b <= 9; b++)

{

for(c = 0; c <= 9; c++)

{

for(d = 0; d <= 9; d++)

{

for(e = 0; e <= 9; e++)

{

if(a != 4 && b != 4 && c != 4 && d != 4 && e !=4)

{

count++;

}

}

}

}

}

}

cout<<count<<endl;

return 0;

}

输出为:    52488

第2题:计算1千天后的日期

题目大意

  2014-11-09再过1000天是哪一日?

解题分析:

我想这里题目,对于大家来说分析的时候难点就在于那年是闰年,那年是平年

那么从2014到2017年之间2016年是闰年,因此这一年就是365天,

这道题,我是手算的。

答案是:

2017-08-05

重点是要按照格式提交。

第3题:竖式加法

题目大意

  祥 瑞 生 辉

  三 羊 献 瑞

????????

 三 羊 生 瑞 气

 

 

题目用了8个不同的汉字,表示0~9里八种不同的数字。组成两个数值相加,等于第三个数值。

求三羊献瑞”对应到数字是多少?

解题分析:

第一种暴力搜索:

我假设结果中进位的是1,那么三对应的就是数字1.

接下来定义变量。

a b c d

+ 1  e  f  b

------------------

1 e c b g

代码:

这段代码输三个结果,把每个结果带进去试一下就知道那个是了。

#include <iostream>

#include <cstdio>

using namespace std;

int main()

{

int a, b, c, d, e, f, g;

for(a = 1; a <= 9; a++)

{

for(b = 0; b <= 9; b++)

{

for(c = 0; c <= 9; c++)

{

for(d = 0; d <= 9; d++)

{

for(e = 0; e <= 9; e++)

{

for(f = 0; f <= 9; f++)

{

for(g = 0; g <= 9; g++)

{

if((a * 1000 + b * 100 + c * 10 + d) + (1000 + e * 100 + f * 10 + b) == (10000 + e * 1000 + c * 100 + b * 10 + g))

{

if(a != 1 && b != 1 && c != 1 && d != 1 && e != 1 && f != 1)

{

if(a != b && a != c && a != d && a !=e && a != f && a != g && b != c && b != d && b != e && b != f && b != g && c != d && c != e && c != f && c != g && d != e && d != f && d != g && e != f && e != g && f !=
g)

{

cout<<1 * 1000 + e * 100 + f * 10 + b<<endl;

}

}

}

}

}

}

}

}

}

}

return 0;

}

第二种解法:

全排列方法:

代码:

#include <iostream>

#include <cstdio>

#include <algorithm>

using namespace std;

int main()

{

int a[10];

for(int i = 0; i <= 9; i++)

{

a[i] = i;

}

do

{

if(!a[2] || !a[6])

continue;

int x = a[2] * 1000 + a[3] * 100 + a[4] * 10 + a[5];

int y = a[6] * 1000 + a[7] * 100 + a[8] * 10 + a[3];

int z = a[6] * 10000 + a[7] * 1000 + a[4] * 100 + a[3] * 10 + a[9];

if(x + y == z)

cout <<y<<endl;

}while(next_permutation(a, a + 10));

return 0;

}

=======================================================================================

代码填空

=======================================================================================

第4题:古怪的星号修饰符

题目大意

  是道代码填空题,主要是完成一个字符串s,按宽度width截断后,在固定宽度为width,两边为符号’|’的居中输出。

  难点是题目给出了printf(“%*s%s%*s”,___),要求填printf的实参列表。

这道题看的时候觉得有点坑,因为自己不懂printf("%*s %s %*s", );;的意思,我开始还以为是指针那一块的。

现在把网上的给大家分享:

有些童鞋可能知道scanf里用*修饰符,是起到过滤读入的作用。比如一个有三列数值的数据,我只想得到第2列数值,可以在循环里用scanf(“%*d%d%*d”, a[i])来读入第i行的第2个数值到a[i]。

  * 修饰符在printf中的含义完全不同。如果写成printf(“%6d”, 123),很多童鞋应该就不会陌生了,这是设置域宽的意思。同理,%6s也是域宽。* 修饰符正是用来更灵活的控制域宽。使用%*s,表示这里的具体域宽值由后面的实参决定,如printf(“%*s”, 6, “abc”)就是把”abc”放到在域宽为6的空间中右对齐。

  明白了 * 是用变量来控制域宽,那么这题就简单了,这里应该填写5个实参。然后字符长度的计算应该用buf而不是s,因为buf才是截断后的长度,用s的话,如果s长度超过了width-2,效果就不对了。

类似使用说明的代码如下:

#include <iostream>

#include <cstdio>

#include <cstring>

using namespace std;

int main() {

char s[100] = "abcd1234";

char buf[1000];

int width = 20;

strcpy(buf, s);

buf[width-2] = 0;

printf("|%*s%s%*s|\n", (width-strlen(buf)-2)/2, "", buf, (width-strlen(buf)-2)/2, "");

return 0;

}

第5题:补充全排列的回溯算法

题目大意

  1,2,3…9 这九个数字组成一个分数,其值恰好为1/3,如何组法?

与第3题一样可以用全排列暴力,但这题是代码填空题,且已经手写一部分全排列算法,我们负责补充其中一行代码。

  写全排就是用回溯的思想,直接猜到for循环里的第三行,应该就是把第一行的交换操作再交换回来~~复制for里的第一行代码,运行下程序,还不放心就调试下,看看数组是不是有按字典序在变化就行了。

  答案:{t=x[k]; x[k]=x[i]; x[i]=t;}

======================================================================================

填空

=======================================================================================

第6题:加号改乘号

题目大意

  把1+2+3+…+48+49中的两个加号改成乘号(修改位置不能相邻),使得式子的结果由1225变为2015。

解题分析:

用双循环暴力两个乘号的位置,计算在数字i、j后的加号改为乘号,式子数值的变化即可,注意j的起始位置为i+2。

代码:

#include <iostream>

#include <cstdio>

using namespace std;

int main()

{

for(int i = 1; i <= 48; i++)

{

for(int j = i + 2; j <= 48; j++)

{

if(1225 - i - (i + 1) - j - (j + 1) == 2015 - i * (i + 1) - j * (j + 1))

cout<<i<<endl;

}

}

return 0;

}

第7题:牌型种数

题目大意

 

原题:

小明被劫持到X赌城,被迫与其他3人玩牌。

一副扑克牌(去掉大小王牌,共52张),均匀发给4个人,每个人13张。

这时,小明脑子里突然冒出一个问题:

如果不考虑花色,只考虑点数,也不考虑自己得到的牌的先后顺序,自己手里能拿到的初始牌型组合一共有多少种呢?

请填写该整数,不要填写任何多余的内容或说明文字。

解题分析:

这里也是两种方法, 暴力搜索, 动态规划(DP)。

第一种:

暴力方法:

#include <iostream>

#include <cstdio>

using namespace std;

int main()

{

int a[13];

static int count;

int ans = 0;

for(a[0]=0; a[0]<=4; a[0]++)

{

for(a[1]=0; a[1]<=4; a[1]++)

{

for(a[2]=0; a[2]<=4; a[2]++)

{

for(a[3]=0; a[3]<=4; a[3]++)

{

for(a[4]=0; a[4]<=4; a[4]++)

{

for(a[5]=0; a[5]<=4; a[5]++)

{

for(a[6]=0; a[6]<=4; a[6]++)

{

for(a[7]=0; a[7]<=4; a[7]++)

{

for(a[8]=0; a[8]<=4; a[8]++)

{

for(a[9]=0; a[9]<=4; a[9]++)

{

for(a[10]=0; a[10]<=4; a[10]++)

{

for(a[11]=0; a[11]<=4; a[11]++)

{

for(a[12]=0; a[12]<=4; a[12]++)

{

if(a[0]+a[1]+a[2]+a[3]+a[4]+a[5]+a[6]+a[7]+a[8]+a[9]+a[10]+a[11]+a[12]==13)

{

count++;

ans = count;

}

}

}

}

}

}

}

}

}

}

}

}

}

}

cout<<ans<<endl;

return 0;

}

具体参考:

http://blog.csdn.net/u012965373/article/details/45008255

解法二:

动态规划, DP。

假设牌是从1到13按顺序取的,dp[i][j]表示取到第i号的牌,目前总共有j张牌的取法总数,那么有状态转移方程(注意公式没考虑边界处理):

  如图:

代码:

#include <iostream>

#include <cstdio>

using namespace std;

typedef long long LL;

LL dp[14][14]; // dp[i][j]: 当前到第i张牌,总共有j张牌时的解的个数

int main() {

dp[1][0] = dp[1][1] = dp[1][2] = dp[1][3] = dp[1][4] = 1;

for (int i = 2; i <= 13; i++) {

for (int k = 0; k <= 13; k++) {

if (k - 4 >= 0) dp[i][k] += dp[i-1][k-4];

if (k - 3 >= 0) dp[i][k] += dp[i-1][k-3];

if (k - 2 >= 0) dp[i][k] += dp[i-1][k-2];

if (k - 1 >= 0) dp[i][k] += dp[i-1][k-1];

dp[i][k] += dp[i-1][k];

}

}

cout << dp[13][13] << endl;

return 0;

}

第8题:计算房子间曼哈顿距离

题目大意

  房子按S形摆放,如

  1 2 3

  6 5 4

  7 8 ……

  现输入每行的宽度w,计算出任意两个房子m、n的曼哈顿距离(横向距离+竖向距离)。

解题分析:

直接计算两点的距离就可以了。

代码:

#include <iostream>

#include <cstdio>

#include <cmath>

using namespace std;

Fun(int w, int n, int& x, int& y)

{

x = (n - 1) / w + 1;

y = n % w;

if(y == 0)

y = w;

if(x % 2 == 0)

y = w - y + 1;

}

int main()

{

int w, m, n;

int x1, y1, x2, y2;

cin>>w>>m>>n;

Fun(w, m, x1, y1);

Fun(w, n, x2, y2);

cout<<abs(x1 - x2) + abs(y1 - y2)<<endl;

return 0;

}

第9题:垒骰子(矩阵快速幂模)

题目大意

   输入n,m,表示用n个骰子,在m个约束条件下,从下往上叠成一列。接下来m行,每行有两个数a,b,表示骰子之间数字a、b两个所在面不能拼接。

   问这n个骰子一共有多少种垒法?答案对1e9+7取余。

注意骰子摆好后,四个方向均能转动,即样例输入:

   2  1

   1  2

的样例输出是:

   544

矩阵快速幂基础

  请读者先看这篇文章:hdu5171 GTY’s birthday gift(BestCoder Round #29 1002),或阅读其他矩阵快速幂模文章,自行补基础。我给出的这篇文章,写了个矩阵快速幂模的类模板,将在下面的代码中使用。实际解题中,可以根据特殊问题写特殊代码,不必写出通用的矩阵类,加快解题速度。

  

题解

  比赛中,不使用模板,建议数组从下标1开始使用。这里为了和模板配合,所以假设骰子从0开始编号。可以发现规律,如果骰子的a面为0,1,2,那么a的对面数值就是a+3;相反,如果骰子的a面为3,4,5,那么a的对面数值就是a-3。这个由当前面变换到对面的操作可以用公式完成:(a+3)%6。

  现在用一个bool数组isLimit[6][6]来存储,isLimit[i][j]为真,代表当前骰子i面朝上,不能接j面朝上的骰子。

  矩阵快速幂模,主要是找到A^(n-1) * X中的A和X。那么这里的X向量,X[i]初值就是第一个骰子i面朝上的方法数,一共是4种。即X[0]~X[5]均为4。

  A[i][j]就是当前骰子i面朝上,接j面朝上后,原方法数要乘上的因子。故A[i][j]可以由isLimit直接得到。如果i->j被限制,乘因子就是0,否则就是4。

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

/*矩阵类(用于快速幂模)
  1、T是整型类型,N是方阵大小,MOD是取余的值
  2、Eye是单位阵
*/
template <typename T, const int N, const int MOD>
class Matrix {
    T val[N][N];

public:
    Matrix() { memset(val, 0, sizeof(val)); }
    Matrix(T a[N][N]) { memcpy(val, a, sizeof(val)); }

    Matrix operator*(const Matrix& c) const {
        Matrix res;
        for (int i = 0; i < N; ++i)
            for (int j = 0; j < N; ++j)
                for (int k = 0; k < N; ++k) {
                    res.val[i][j] += val[i][k] * c.val[k][j];
                    //防止矩阵元素变为负数,若不需要,去掉"+MOD"
                    res.val[i][j] = (res.val[i][j] + MOD) % MOD;
                }
        return res;
    }

    Matrix& operator*=(const Matrix& c) {
        *this = *this * c;
        return *this;
    }

    Matrix operator^(int k) const { //返回*this^k
        Matrix res = Eye();
        Matrix step(*this);
        while (k) {
            if (k & 1) res *= step;
            k >>= 1;
            step *= step;
        }
        return res;
    }

    Matrix Eye() const {
        Matrix a;
        for (int i = 0; i < N; i++) a.val[i][i] = 1;
        return a;
    }

    void out() const {
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++)
                cout << val[i][j] << " ";
            cout << "\n";
        }
    }

    T* operator[](int i) { return val[i]; }
};

typedef long long LL;
const int MOD = 1e9 + 7;

int main() {
    int n, m;
    Matrix<LL,6,MOD> A, X, Y;
    bool isLimit[6][6];

    // 输入处理
    cin >> n >> m;
    memset(isLimit, false, sizeof(isLimit));
    for (int i = 0; i < m; i++) {
        int a, b;
        cin >> a >> b;
        isLimit[a-1][ (b+2)%6 ] = true;
        isLimit[b-1][ (a+2)%6 ] = true;
    }

    // 初始化A
    for (int i = 0; i < 6; i++) {
        for (int j = 0; j < 6; j++) {
            A[i][j] = (!isLimit[i][j]) * 4;
        }
    }

    // 初始化X
    for (int i = 0; i < 6; i++) X[i][0] = 4;

    // 计算Y及答案
    Y = (A^(n-1)) * X;
    LL sum = 0;
    for (int i = 0; i < 6; i++) sum += Y[i][0];
    cout << sum % MOD << endl;

    return 0;
}

第10题:树形DP

题目大意

  在一颗树中,每个点都有一个权值,有正有负。

  要求找一个连通的点集S,使得累加和最大。

题解

  树形DP不是我熟悉的模块,这个坑就交给别人填了

  树形DP参考博客:“树形DP(HDOJ1011 2196 4003 5148 POJ2342)”,及下方__M子__提供的代码:

 #include<iostream>
 #include<algorithm>
 #include<cstdio>
 #include<vector>
using namespace std;
typedef long long LL;
const int MAXN=100000+10;
const int INF=-1000000-10;
LL dp[MAXN][2];
vector<int>tree[MAXN];
LL w[MAXN];

void dfs(int p,int fa){
    dp[p][0]=max(dp[p][0],w[p]);
    dp[p][1]=max(dp[p][1],w[p]);
    for(int i=0;i<tree[p].size();i++){
        int son=tree[p][i];
        if(son^fa){
            dfs(son,p);
            dp[p][0]=max(dp[p][0],dp[son][0]);
            if(dp[son][1]>0)dp[p][1]+=dp[son][1];
        }
    }
    dp[p][0]=max(dp[p][0],dp[p][1]);
}

int main(){
    int n,a,b;
    cin>>n;
    for(int i=1;i<=n;i++)cin>>w[i];
    for(int i=1;i<=n;i++){dp[i][0]=INF;dp[i][1]=INF;}
    for(int i=1;i<n;i++){
        cin>>a>>b;
        tree[a].push_back(b);
        tree[b].push_back(a);
    }
    dfs(1,-1);
    cout<<dp[1][0]<<"\n";
    return 0;
}
时间: 2024-10-11 19:45:53

2015年蓝桥杯省赛B组C/C++(试题+答案)的相关文章

2018 蓝桥杯省赛 B 组模拟赛(一)

2018 蓝桥杯省赛 B 组模拟赛(一) A.今天蒜头君带着花椰妹和朋友们一起聚会,当朋友们问起年龄的时候,蒜头君打了一个哑谜(毕竟年龄是女孩子的隐私)说:“我的年龄是花椰妹年龄个位数和十位数之和的二倍”. 花椰妹看大家一脸懵逼,就知道大家也不知道蒜头君的年龄,便连忙补充道:“我的年龄是蒜头君个位数和十位数之和的三倍”. 请你计算:蒜头君和花椰妹年龄一共有多少种可能情况? 提醒:两位的年龄都是在 [10,100)[10,100) 这个区间内. 题解: 暴力枚举 answer: 1 代码如下: #

2015蓝桥杯 国赛B组 密文搜索

福尔摩斯从X星收到一份资料,全部是小写字母组成. 他的助手提供了另一份资料:许多长度为8的密码列表. 福尔摩斯发现,这些密码是被打乱后隐藏在先前那份资料中的. 请你编写一个程序,从第一份资料中搜索可能隐藏密码的位置.要考虑密码的所有排列可能性. 数据格式: 输入第一行:一个字符串s,全部由小写字母组成,长度小于1024*1024 紧接着一行是一个整数n,表示以下有n行密码,1<=n<=1000 紧接着是n行字符串,都是小写字母组成,长度都为8 要求输出: 一个整数, 表示每行密码的所有排列在s

2015浙江省蓝桥杯c/c++B组个人题解

奖券数目 有些人很迷信数字,比如带"4"的数字,认为和"死"谐音,就觉得不吉利. 虽然这些说法纯属无稽之谈,但有时还要迎合大众的需求.某抽奖活动的奖券号码是5位数(10000-99999),要求其中不要出现带"4"的号码,主办单位请你计算一下,如果任何两张奖券不重号,最多可发出奖券多少张. 52488 #include <iostream> #include <cstdio> #include <cstring>

2015年蓝桥杯C/C++ B组题目题解

1. 输入一个字符串,求它包含多少个单词.单词间以一个或者多个空格分开. 第一个单词前,最后一个单词后也可能有0到多个空格.比如:" abc xyz" 包含两个单词,"ab c xyz " 包含3个单词. 如下的程序解决了这个问题,请填写划线部分缺失的代码. 注意:只填写划线部分的代码,不要填写任何多余的内容.比如已经存在的小括号,注释或说明文字等. #include <stdio.h> #include <string.h> #includ

蓝桥杯省赛总结

3.28号下午查到了成绩,还行,考到B组省赛一等奖,可以进入决赛. 成绩的结果还是很意外的,因为自己没怎么准备,试题有的题就是瞎写的,只看了官网的两个辅导视频.剩下的懒了 就没看... 面对这电脑,看着题目,才意识到自己的不足之处.以前总是急功近利,想着学几门编程语言,现在才真正明白,语言只是个工具,自己要懂得利用一门编程语言解决实际的问题,并且考虑到优化提高的办法,这样才能提高自己能力,而不是会多少编程语言. 今天记录这些,就是激励自己,以一颗平静的心去学习.在记录,总结,展望中不断地提高自己

2016 第七届蓝桥杯 c/c++ B组省赛真题及解题报告

2016 第七届蓝桥杯 c/c++ B组省赛真题及解题报告 勘误1:第6题第4个 if最后一个条件粗心写错了,答案应为1580. 条件应为abs(a[3]-a[7])!=1,宝宝心理苦啊.!感谢zzh童鞋的提醒. 勘误2:第7题在推断连通的时候条件写错了,后两个if条件中是应该是<=12 落了一个等于号.正确答案应为116. 1.煤球数目 有一堆煤球.堆成三角棱锥形.详细: 第一层放1个, 第二层3个(排列成三角形), 第三层6个(排列成三角形), 第四层10个(排列成三角形). -. 假设一共

第七届蓝桥杯C语言C组-(自己懂的题目)

第七届蓝桥杯C语言C组-(自己懂的题目) 表示刚刚查了成绩,省赛一等奖,有资格去北京了,然后写一下总结, 先来写一下我懂的题目,毕竟我也是菜鸟,听说国赛比预赛难几个等级... 第一题 报纸页数 X星球日报和我们地球的城市早报是一样的, 都是一些单独的纸张叠在一起而已.每张纸印有4版. 比如,某张报纸包含的4页是:5,6,11,12, 可以确定它应该是最上边的第2张报纸. 我们在太空中捡到了一张X星球的报纸,4个页码分别是: 1125,1126,1727,1728 请你计算这份报纸一共多少页(也就

第七届蓝桥杯省赛7:剪邮票

第七届蓝桥杯省赛7:剪邮票 如[图1.jpg], 有12张连在一起的12生肖的邮票. 现在你要从中剪下5张来,要求必须是连着的. (仅仅连接一个角不算相连) 比如,[图2.jpg],[图3.jpg]中,粉红色所示部分就是合格的剪取. 请你计算,一共有多少种不同的剪取方法. 请填写表示方案数目的整数. 注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字. 解决思路:先将所有五个一组的情况遍历,然后用广度优先判断是否连通. 我在选五个一组的时候是用的 for 先选出第几个邮票,然后将其

2015年第六届蓝桥杯C/C++B组省赛题目解析

一.奖券数目 有些人很迷信数字,比如带“4”的数字,认为和“死”谐音,就觉得不吉利.虽然这些说法纯属无稽之谈,但有时还要迎合大众的需求.某抽奖活动的奖券号码是5位数(10000-99999),要求其中不要出现带“4”的号码,主办单位请你计算一下,如果任何两张奖券不重号,最多可发出奖券多少张. 请提交该数字(一个整数),不要写任何多余的内容或说明性文字. 分析:直接枚举10000-99999之间的数字,如果带4,直接排除:不带4的,记录一次,直到枚举完后输出. #include <iostream