第九届蓝桥杯(省赛)C++C组真题题解


剩余题目同B组真题相同,已给出B组真题题目链接:博客链接

题目链接

C组真题(剩余题目同B组真题相同,已给出B组真题题目链接)

题目结构

题目类型分值
第一题结果填空5分
第二题结果填空9分
第三题结果填空13分
第四题结果填空17分
第五题代码填空7分
第六题代码填空11分
第七题程序设计19分
第八题程序设计21分
第九题程序设计23分
第十题程序设计25分

第一题 哪天返回

  • 问题重现

    小明被不明势力劫持。后莫名其妙被扔到x星站再无问津。
    小明得知每天都有飞船飞往地球,但需要108元的船票,而他却身无分文。
    他决定在x星战打工。好心的老板答应包食宿,第1天给他1元钱。
    并且,以后的每一天都比前一天多2元钱,直到他有足够的钱买票。
    请计算一下,小明在第几天就能凑够108元,返回地球。

    输出

    输出一个整数表示答案

  • 解题思路

    就是一个等差数列,利用公式求解可得。

  • 代码

/**
  *@filename:哪天返回
  *@author: pursuit
  *@CSDNBlog:unique_pursuit
  *@email: 2825841950@qq.com
  *@created: 2021-04-09 13:57
**/
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 100000 + 5;
const int mod = 1e9+7;


void solve(){
}
int main(){
    //等差数列求和公式得解。公差为2.
    int n=1;
    while(n*1+n*(n-1)*2/2<108){
        n++;
    }
    cout<<n<<endl;//11
    solve();
    return 0;
}
  • 答案

    11 11 11


第二题 猴子分香蕉

  • 问题重现

    5只猴子是好朋友,在海边的椰子树上睡着了。这期间,有商船把一大堆香蕉忘记在沙滩上离去。
    第1只猴子醒来,把香蕉均分成5堆,还剩下1个,就吃掉并把自己的一份藏起来继续睡觉。
    第2只猴子醒来,重新把香蕉均分成5堆,还剩下2个,就吃掉并把自己的一份藏起来继续睡觉。
    第3只猴子醒来,重新把香蕉均分成5堆,还剩下3个,就吃掉并把自己的一份藏起来继续睡觉。
    第4只猴子醒来,重新把香蕉均分成5堆,还剩下4个,就吃掉并把自己的一份藏起来继续睡觉。
    第5只猴子醒来,重新把香蕉均分成5堆,哈哈,正好不剩!
    请计算一开始最少有多少个香蕉。

    输入

    输出

    输出一个整数表示答案

  • 解题思路

    一定要注意均分这个点,说明是可以整除的,我们只要枚举判断即可。

  • 代码

/**
  *@filename:猴子分香蕉
  *@author: pursuit
  *@CSDNBlog:unique_pursuit
  *@email: 2825841950@qq.com
  *@created: 2021-04-09 14:02
**/
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 100000 + 5;
const int mod = 1e9+7;

//一定要注意均分这个点。假设一开始有香蕉x。
//说明(x-1) mod 5 我们设(x-1)*4/5=y
//说明(y-2)mod 5,我们设(y-2)*4/5=z
//则(z-3) mod 5,我们设(z-3)*4/5=u
//则(u-4) mod 5,我们设(u-4)*4/5=v
//则v mod 5;我们枚举x判断。
void solve(){
}
int main(){
    int x,y,z,u,v;//3141
    for(x=6;;x+=5){
        y=(x-1)*4/5;
        if((y-2)>0&&(y-2)%5==0){
            z=(y-2)*4/5;
            if((z-3)>0&&(z-3)%5==0){
                u=(z-3)*4/5;
                if((u-4)>0&&(u-4)%5==0){
                    v=(u-4)*4/5;
                    if(v>0&&v%5==0){
                        cout<<x<<endl;
                        break;
                    }
                }
            }
        }
    }
    solve();
    return 0;
}
  • 答案

    3141 3141 3141


第五题 书号验证

  • 问题重现

    2004年起,国际ISBN中心出版了《13位国际标准书号指南》。

    原有10位书号前加978作为商品分类标识;校验规则也改变。

    校验位的加权算法与10位ISBN的算法不同,具体算法是:

    1、 用1分别乘ISBN的前12位中的奇数位(从左边开始数起),用3乘以偶数位,乘积之和以10为模,

    2、10与模值的差值再对10取模(即取个位的数字)即可得到校验位的值,其值范围应该为0~9。

    下面的程序实现了该算法,请仔细阅读源码,填写缺失的部分。

    // 验证成功返回 1,否则返回 0 
    int f(const char* s)
    {
    int k=1;
    int sum = 0;
    int i; 
    for(i=0; s[i]!='\0'; i++){
    	char c = s[i];
    	if(c=='-' || c==' ') continue;
    	sum += _________________________________________ ;  //填空
    	k++;
    	if(k>12) break; 
    }
    
    while(s[i]!='\0') i++;
    
    return (s[i-1]-'0') == (10-sum % 10)%10;
    }
    
    int main()
    {
    printf("%d\n",f("978-7-301-04815-3"));
    printf("%d\n",f("978-7-115-38821-6"));	
    return 0;
    }
    
  • 解题思路

    横线上所需填的即是我们需要判断是奇数位还是偶数位,由于只有一行,所以用?:条件表达式语句即可。

  • 答案

    (c-'0')*(k%2?1:3)


第六题 稍小分数

  • 问题重现

    回到小学----

    真分数:分子小于分母的分数

    既约分数:分子分母互质,也就是说最大公约数是1

    x星球数学城的入口验证方式是:

    屏幕上显示一个真分数,需要你快速地找到一个比它小的既约分数,要求这个分数越大越好。
    同时限定你的这个分数的分母不能超过100。

    如下代码很暴力地解决了这个问题,请仔细分析,并填写划线部分缺失的代码。

    int gcd(int a, int b)
    {
    if(b==0) return a;
    return gcd(b, a%b);	
    }
    int main()
    {
    // 这是屏幕上显示的那个分数 a/b
    int a = 7;
    int b = 13;
    
    int m,n;
    int max_a = 0;
    int max_b = 1; 
    
    for(n=100; n>1; n--){
    	for(m=n-1; m>=1; m--){
    		if(m*b<a*n && gcd(m,n)==1){
    			if( __________________________________ ){  //填空
    				max_a = m;
    				max_b = n;
    				break;
    			}
    		}
    	}
    }
    
    printf("%d/%d\n", max_a, max_b);	
    return 0;
    }
    
    
  • 解题思路

    由题意知此if判断更新最大值,所以我们需要判断是否符合条件,由于都是整型数据且上一个if其实已经提示了,将分数之间的比较转化即 a / b > c / d ≡ a ∗ d > c / b a/b>c/d\equiv a*d>c/b a/b>c/dad>c/b

  • 答案

    m*max_b>n*max_a


第七题 次数差

  • 问题重现

    x星球有26只球队,分别用a~z的26个字母代表。他们总是不停地比赛。
    在某一赛段,哪个球队获胜了,就记录下代表它的字母,这样就形成一个长长的串。
    国王总是询问:获胜次数最多的和获胜次数最少的有多大差距?

    输入

    输入存在多组数据,对于每组数据:
    输入一行包含一个串,表示球队获胜情况(保证串的长度<1000)

    输出

    对于每组数据:输出一个数字,表示出现次数最多的字母比出现次数最少的字母多了多少次。

    样例输入

    abaabcaa
    bbccccddaaaacccc
    

    样例输出

    4
    6
    
  • 解题思路

    利用map容器记录,最后遍历记录最大值和最小值即可得出答案。

  • 代码

/**
  *@filename:次数差
  *@author: pursuit
  *@CSDNBlog:unique_pursuit
  *@email: 2825841950@qq.com
  *@created: 2021-04-09 14:17
**/
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 100000 + 5;
const int mod = 1e9+7;

map<char,int> p;
string s;
void solve(){
    for(auto &x:s){
        p[x]++;
    }
    int minn=1000,maxx=0;
    for(auto &x:p){
        minn=min(x.second,minn);
        maxx=max(x.second,maxx);
    }
    cout<<maxx-minn<<endl;
}
int main(){
    while(cin>>s){
        p.clear();
        solve();
    }
    return 0;
}

第八题 等腰三角形

  • 问题重现

    本题目要求你在控制台输出一个由数字组成的等腰三角形。
    具体的步骤是:

    1. 先用1,2,3,…的自然数拼一个足够长的串
    2. 用这个串填充三角形的三条边。从上方顶点开始,逆时针填充。比如,当三角形高度是8时 :
      在这里插入图片描述

    输入

    输入存在多组数据,对于每组数据:
    输入一行包含一个正整数n(3<n<300),表示三角形的高度

    输出

    对于每组测试数据输出用数字填充的等腰三角形。
    为了便于测评,我们要求空格一律用"."代替。

    样例输入

    5
    10
    

    样例输出

    ....1
    ...2.1
    ..3...2
    .4.....1
    567891011
    .........1
    ........2.2
    .......3...2
    ......4.....2
    .....5.......1
    ....6.........2
    ...7...........0
    ..8.............2
    .9...............9
    1011121314151617181
    
  • 解题思路

    首先我们要做的就是将这些整数连成一个串,然后根据坐标绘制即可。注意坐标的变化。

  • 代码

/**
  *@filename:等腰三角形
  *@author: pursuit
  *@CSDNBlog:unique_pursuit
  *@email: 2825841950@qq.com
  *@created: 2021-04-09 16:45
**/
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 300 + 5;
const int mod = 1e9+7;

int n;
char graph[maxn][maxn];
string s;
void solve(){
    for(int i=0;i<n;i++){
        for(int j=0;j<n+i;j++){
            graph[i][j]='.';
        }
    }
    //开始填数。
    int index=0;
    //开始左边。
    for(int i=0,j=n-1;i<n-1;i++,j--){
        graph[i][j]=s[index++];
    }
    //开始底边。
    for(int i=n-1,j=0;j<2*n-1;j++){
        graph[i][j]=s[index++];
    }
    for(int i=n-2,j=2*n-3;i>0;i--,j--){
        graph[i][j]=s[index++];
    }
    for(int i=0;i<n;i++){
        for(int j=0;j<n+i;j++){
            cout<<graph[i][j];
        }
        cout<<endl;
    }
}
int main(){
    s="";
    for(int i=1;i<=200;i++){
        s+=to_string(i);
    }
    while(cin>>n){
        //cout<<s.size()<<endl;
        solve();
    }
    return 0;
}

第九题 小朋友崇拜圈

  • 问题重现

    班里N个小朋友,每个人都有自己最崇拜的一个小朋友(也可以是自己)。
    在一个游戏中,需要小朋友坐一个圈,
    每个小朋友都有自己最崇拜的小朋友在他的右手边。
    求满足条件的圈最大多少人?
    小朋友编号为1,2,3,…N

    输入

    输入第一行,一个整数N(3<N<100000)
    接下来一行N个整数,由空格分开。表示每位小朋友崇拜的小朋友的编号。

    输出

    输出一个整数,表示满足条件的最大圈的人数。

    样例输入

    9
    3 4 2 5 3 8 4 6 9
    

    样例输出

    4
    

    提示

    如图所示,崇拜关系用箭头表示,红色表示不在圈中。
    显然,最大圈是[2 4 5 3] 构成的圈
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LFYanJ1U-1618148068902)(第九届蓝桥杯(省赛)C++C组真题题解.assets/20191118000755_64238.png)]

  • 解题思路

    我们可以用一个数组friends来表示,其中friends[i]表示第 i i i个小朋友崇拜的人。那么,我们就可以用 d f s dfs dfs去搜索环的长度了,要注意的就是搜索完之后标记的清除。

  • 代码

/**
  *@filename:小朋友崇拜圈
  *@author: pursuit
  *@CSDNBlog:unique_pursuit
  *@email: 2825841950@qq.com
  *@created: 2021-04-09 17:26
**/
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 100000 + 5;
const int mod = 1e9+7;

int n;//n个小朋友。
int friends[maxn];
int ans,maxx;
bool vis[maxn];
void dfs(int i,int obj){
    if(vis[i]&&i!=obj){
        return;
    }
    if(vis[i]&&i==obj){
        //说明到达了。形成了一个回环。
        maxx=max(ans,maxx);
        return;
    }
    ans++;
    vis[i]=true;
    dfs(friends[i],obj);
    vis[i]=false;
}
void solve(){
    ans,maxx=0;
    for(int i=1;i<=n;i++){
        ans=0;
        dfs(i,i);
    }
    cout<<maxx<<endl;
}
int main(){
    while(cin>>n){
        int temp;
        for(int i=1;i<=n;i++){
            cin>>temp;
            friends[i]=temp;
        }
        solve();
    }
    return 0;
}

第十题 耐摔指数

  • 问题重现

    x星球的居民脾气不太好,但好在他们生气的时候唯一的异常举动是:摔手机。
    各大厂商也就纷纷推出各种耐摔型手机。
    x星球的质监局规定了手机必须经过耐摔测试,并且评定出一个耐摔指数来,之后才允许上市流通。
    x星球有很多高耸入云的高塔,刚好可以用来做耐摔测试。
    塔的每一层高度都是一样的,与地球上稍有不同的是,他们的第一层不是地面,而是相当于我们的2楼。
    如果手机从第7层扔下去没摔坏,但第8层摔坏了,则手机耐摔指数=7。
    特别地,如果手机从第1层扔下去就坏了,则耐摔指数=0。
    如果到了塔的最高层第n层扔没摔坏,则耐摔指数=n
    为了减少测试次数,从每个厂家抽样3部手机参加测试。
    如果已知了测试塔的高度,并且采用最佳策略,在最坏的运气下最多需要测试多少次才能确定手机的耐摔指数呢?

    输入

    输入存在多组测试数据,每组测试数据输入一个整数n(3<n<10000),表示测试塔的高度。

    输出

    对于每组测试数据,输出一个整数,表示最多测试多少次。

    样例输入

    3
    7
    

    样例输出

    2
    3
    

    提示

    1. 手机a从2楼扔下去,坏了,就把b手机从1楼扔;否则a手机继续3层扔下
    2. a手机从4层扔,坏了,则下面有3层,b,c 两部手机2次足可以测出指数;

    若是没坏,手机充足,上面5,6,7 三层2次也容易测出。

  • 解题思路

    我们试想,如果只有一个手机,那么直接暴力枚举就是答案了。可是现在有三个手机。二分?可以做吗?我们发现,对于二分法,如果每次枚举的点都碎了,那就无法得到答案了,显然不行,对于有无限个手机的时候这个才是最佳决策。那么这道题我们该怎么做呢?其实这道题蕴含着好多决策点,我们测一次楼层的时候即是一个状态,而且这状态显然是相互转移的,所以动态规划才是解决这道问题的关键。我们用 d p [ i ] [ j ] dp[i][j] dp[i][j]表示现在还有 i i i部手机且待测楼层有 j j j层时,最坏运气下的最少的测试次数。那么我们测试 k ( k ∈ [ 1 , j ] k(k\in [1,j] k(k[1,j]层时则有两种情况:

    1. 如果当前测的手机坏了,那么手机数量减一,并去下一层测试,此时待测楼层为 k − 1 k-1 k1

    2. 如果当前测的手机没坏,那么就去上一层测试,此时 j − k j-k jk

    我们想要的状态为 d p [ 3 ] [ n ] dp[3][n] dp[3][n],我们已知的状态即是只有一个手机的时候,我们运气最差只能从 1 1 1测到 j j j,这样进行状态转移即可。

  • 代码

/**
  *@filename:耐摔指数
  *@author: pursuit
  *@CSDNBlog:unique_pursuit
  *@email: 2825841950@qq.com
  *@created: 2021-04-10 00:20
**/
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 10000 + 5;
const int mod = 1e9+7;

int n;
int dp[4][maxn];//dp[i][j]表示有i部手机且待测j个楼层的运气最差的最少测试次数。
void solve(){
    for(int i=1;i<=3;i++){
        for(int j=1;j<=n;j++){
            //不管有几部手机,最坏的次数就是从1到j测下去。
            dp[i][j]=j;
        }
    }
    //接下来开始模拟,
    for(int i=2;i<=3;i++){
        for(int j=1;j<=n;j++){
            //模拟1~j的测试情况。
            //如果坏了,则手机数量减1,并去下一层测试,否则没摔坏就去楼上测试。
            for(int k=1;k<j;k++){
                dp[i][j]=min(dp[i][j],max(dp[i-1][k-1],dp[i][j-k])+1);
            }
        }
    }
    cout<<dp[3][n]<<endl;
}
int main(){
    while(cin>>n){
        solve();
    }
    return 0;
}
posted @ 2022-03-26 16:49  unique_pursuit  阅读(154)  评论(0)    收藏  举报