蓝桥杯2020第十一届C语言B组省赛习题题解

蓝桥杯2020第十一届C语言B组省赛习题题解

  • 试题A.门牌制作
    • 题目分析
    • 代码如下
  • 试题 B 既约分数
    • 题意分析
    • 代码如下:
  • 试题C 蛇形填数
    • 【问题描述】
    • 【问题分析】
    • 【代码如下】
  • 试题D 跑步锻炼
    • 【题目描述】
    • 【问题分析】
    • 【代码如下】
  • 试题E 七段码
    • 【问题描述】
    • 【题意解读】
    • 【代码展示】
    • 【题后反思】
  • 试题F:成绩统计
    • 【题目描述】
    • 【输入格式】
    • 【输出格式】
    • 【样例输入】
    • 【样例输出】
    • 【题意分析】
    • 【代码展示】
  • 试题G:回文日期
    • 【题目描述】
    • 【输入描述】
    • 【输出描述】
      • 【输入】
      • 【输出】
    • 【题意解读】
    • 【代码展示】
  • 试题H:子串分值和
    • 【题目描述】
    • 【题意分析】
    • 【代码展示】
  • 试题I:平面切分
    • 【题目描述】
    • 【题意分析】
    • 【代码展示】
  • 试题J:字串排序
    • 【题目描述】

试题A.门牌制作

蓝桥杯2020第十一届C语言B组省赛习题题解_第1张图片

题目分析

对待这道题目的要求,注意一下几点

  1. 尽量写程序计算 ,避免手写带来的错误;

代码如下

#include
#include
#include
#include
#include

typedef long long ll;
using namespace std;


int main()
{
    int sum = 0;
    int m;
    for(int i=1;i<=2020;i++)
    {
        m = i;
        while(m)
        {
            if(m%10==2)
            {
                sum++;
            }
            m/=10;
        }
    }
    cout<<sum<<endl;
    return 0;
}
//运行结果624

试题 B 既约分数

蓝桥杯2020第十一届C语言B组省赛习题题解_第2张图片

题意分析

  1. 其实就是让你求分子,分母【1,2020】中的最大公约数为一的个数
  2. 可以考虑使用STL的__gcd()函数

代码如下:

#include
#include
#include
#include
#include

typedef long long ll;
using namespace std;

int ans;
int main()
{
    for(int i=1;i<=2020;i++)
    {
        for(int j=1;j<=2020;j++)
        {
            if(__gcd(i,j)==1)
                ans++;
        }
    }
    cout<<ans<<endl;
}

/*
int ans;
int gcd(int a,int b)
{
    if(b==0) return a;
    return gcd(b,a%b);
}

int main()
{

    for(int i=1;i<=2020;i++)
    {
        for(int j=1;j<=2020;j++)
        {
            if(gcd(i,j)==1)
                ans++;
        }
    }
    cout<

试题C 蛇形填数

【问题描述】

如下图所示,小明用从1 开始的正整数“蛇形”填充无限大的矩阵。
蓝桥杯2020第十一届C语言B组省赛习题题解_第3张图片

容易看出矩阵第二行第二列中的数是5。请你计算矩阵中第20 行第20 列的数是多少?

【问题分析】

  1. 这道题目可以观察,可以写代码
  2. 观察发现每次对角线值的差是4的倍数,可以通过递推的方式计算

【代码如下】

#include
#include
#include
#include
#include

typedef long long ll;
using namespace std;

int cnt=1;
int a[100][100];
int main()
{
    int i;
    int x,y;
    for(i=1;i<=40;i++)
    {
        if(i%2==1)
        {
            for(x = i,y=1;x>=1&&y<=i;x--,y++)
                a[x][y] = cnt++;
        }
        else
        {
            for(x = 1,y = i;x<=i && y>=1;x++,y--)
                a[x][y] = cnt++;
        }
    }
    cout<<a[20][20];
}
//761

试题D 跑步锻炼

【题目描述】

小蓝每天都锻炼身体。正常情况下,小蓝每天跑 1 千米。如果某天是周一或者月初(1 日),为了激励自己,小蓝要跑 2 千米。如果同时是周一或月初,小蓝也是跑 2 千米。小蓝跑步已经坚持了很长时间,从 2000 年 1 月 1 日周六(含)到 2020 年10 月 1 日周四(含)。请问这段时间小蓝总共跑步多少千米?

【问题分析】

  1. 这个问题简单暴力的解决方法可以直接遍历每一天,算出每一天的日期,并使用一个计数器计数
  2. 注意闰年

【代码如下】

#include
#include
#include
#include
#include

typedef long long ll;
using namespace std;

int	a[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int main()
{
    int year,month,day,week = 6,sum = 0;
    for(year = 2000;year<=2020;year++)
    {
        if((year%400 == 0) || (year%4 == 0 && year %100!=0))
        {
            a[2] = 29;
        }
        for(month = 1;month <= 12;month++)
        {
            for(day = 1;day<=a[month];day++)
            {
                if(day == 1 || week == 1){
                    sum+=2;
                }
                else
                    sum+=1;

                week = (week+1)%7;
                if(year == 2020 && month == 10 && day == 1)
                {
                    cout<<sum<<endl;//到时间就退出来
                    return 0;
                }
            }
        }
        a[2] = 28;
    }
    return 0;
}
//8879

试题E 七段码

【问题描述】

小蓝要用七段码数码管来表示一种特殊的文字。
蓝桥杯2020第十一届C语言B组省赛习题题解_第4张图片

七段码上图给出了七段码数码管的一个图示,数码管中一共有7 段可以发光的二极管,分别标记为a, b, c, d, e, f, g。小蓝要选择一部分二极管(至少要有一个)发光来表达字符。在设计字符的表达时,要求所有发光的二极管是连成一片的。
例如:b 发光,其他二极管不发光可以用来表达一种字符。
例如:c 发光,其他二极管不发光可以用来表达一种字符。这种方案与上一行的方案可以用来表示不同的字符,尽管看上去比较相似。
例如:a, b, c, d, e 发光,f, g 不发光可以用来表达一种字符。
例如:b, f 发光,其他二极管不发光则不能用来表达一种字符,因为发光的二极管没有连成一片。
请问,小蓝可以用七段码数码管表达多少种不同的字符?

【题意解读】

蓝桥杯2020第十一届C语言B组省赛习题题解_第5张图片

  1. 把每条边相连,建立一个无向图。如果在一个状态之后遍历这个图,用并查集的方式,看是否是一个父节点,如果是一个父节点的话,就是相连的
  2. 学长(大佬)讲的是利用二进制。因为每一个灯仅仅对应着开或者关,正好对应二进制的0和1,用二进制优化,但是我这菜鸡只能理解到这里,还是建图能理解
  3. 实在不行,蓝桥杯比赛现场,你用数学办法推理也行啊。暴力出奇迹

【代码展示】

#include
using namespace std;

int use[10];
int ans,e[10][10],father[10];

void init()
{
    //连边建图
    //a b c d e f g
    //1 2 3 4 5 6 7
    e[1][2] = e[1][6] = 1;
    e[2][1] = e[2][7] = e[2][3] = 1;
    e[3][2] = e[3][4] = e[3][7] = 1;
    e[4][3] = e[4][5] = 1;
    e[5][4] = e[5][6] = e[5][7] = 1;
    e[6][1] = e[6][5] = e[6][7] = 1;
}

int  find(int a)
{
    //并查集
    return (a==father[a])?a:father[a] = find(father[a]);

}
void dfs(int d)
{
    if(d>7)//一个七段管的所有灯的状态已经列举完了
    {
        for(int i=1;i<=7;i++)
        {
            father[i] = i;//注意初始化
        }
        for(int i=1;i<=7;i++)
        {
            for(int j=1;j<=7;j++)
            {
                if(e[i][j] && use[i] && use[j])
                {
                    int fa = find(i),fb = find(j);
                    if(fa != fb)
                    {
                        father[fa] = fb;
                    }
                }
            }
        }

        int k = 0;
        for(int i=1;i<=7;i++)
        {
            if(use[i]&& i == father[i])
                k++;
        }
        if(k==1)//只有一个父节点,就说明他们是相连的
            ans ++;
        return;
    }

    use[d] = 0;//不选
    dfs(d+1);

    use[d]= 1; //选
    dfs(d+1);
    use[d] = 0;//归位
}
int main()
{
    init();
    dfs(1);
    cout<<ans<<endl;
    return 0;
}

【题后反思】

这道题目更彻底的理解了dfs和递归的关系,脑海里更加清晰的认识到dfs的原理了。

试题F:成绩统计

【题目描述】

小蓝给学生们组织了一场考试,卷面总分为 100 分,每个学生的得分都是一个 0 到 100 的整数。
如果得分至少是 60 分,则称为及格。如果得分至少为 85 分,则称为优秀。
请计算及格率和优秀率,用百分数表示,百分号前的部分四舍五入保留整数。

【输入格式】

输入的第一行包含一个整数 n,表示考试人数。
接下来 n 行,每行包含一个 0 至 100 的整数,表示一个学生的得分。

【输出格式】

输出两行,每行一个百分数,分别表示及格率和优秀率。
百分号前的部分四舍五入保留整数。

【样例输入】

7
80
92
56
74
88
100
0

【样例输出】

71%
43%

【题意分析】

这道题的坑点有两个,格式化输出

  1. 输出结果四舍五入
  2. 输出%

【代码展示】

#include
#include
#include
#include
#include

typedef long long ll;
using namespace std;

int main()
{
    int n;
    cin>>n;
    int a = 0,b= 0;
    int x;
    for(int i=1;i<=n;i++)
    {
        cin>>x;
        if(x>=60)
            a++;
        if(x>=85)
            b++;
    }
    printf("%.0lf%%\n%.0lf%%",a/(n/100.0),b/(n/100.0));
    return 0;
}

试题G:回文日期

【题目描述】

2020 年春节期间,有一个特殊的日期引起了大家的注意:2020 年 2 月 2 日。因为如果将这个日期按 “yyyymmdd” 的格式写成一个 8 位数是 20200202,恰好是一个回文数。我们称这样的日期是回文日期。
有人表示 20200202 是 “千年一遇” 的特殊日子。对此小明很不认同,因为不到 2 年之后就是下一个回文日期:20211202 即 2021 年 12 月 2 日。
也有人表示 20200202 并不仅仅是一个回文日期,还是一个 ABABBABA 型的回文日期。对此小明也不认同,因为大约 100 年后就能遇到下一个 ABABBABA 型的回文日期:21211212 即 2121 年 12 月 12 日。算不上 “千年一遇”,顶多算 “千年两遇”。
给定一个 8 位数的日期,请你计算该日期之后下一个回文日期和下一个 ABABBABA 型的回文日期各是哪一天。

【输入描述】

输入包含一个八位整数 NNN,表示日期。
对于所有评测用例,10000101≤N≤8999123110000101 \leq N \leq 8999123110000101≤N≤89991231,保证 NNN 是一个合法日期的 8 位数表示。

【输出描述】

输出两行,每行 1 个八位数。第一行表示下一个回文日期,第二行表示下一个 ABABBABA 型的回文日期。
输入输出样例
示例

【输入】

20200202

【输出】

20211202
21211212
运行限制
最大运行时间:1s
最大运行内存: 256M

【题意解读】

  1. 首先看到八位的整数,还是回文的,出题人是真的恶心,一个一个枚举判断八位数是不是回文的实在是太慢了,学长讲的方法是自己动手构造。我们只要枚举1000到8999这前四位,然后直接构造回文串,存储下来,根据题意查询到即可
  2. 例如1001,我们可以构造成10011001这样的回文串
  3. 同时我们应该注意,并不一定所有的回文串都符合日期格式,所以需要判断
  4. 最后按照输入的时间,进去查询就可以,在找到一个ababbaba型的就好
  5. 一旦考察到年份就要想到闰年这个特殊的家伙

【代码展示】

#include
#include
#include
#include
#include
#include

typedef long long ll;
using namespace std;
int b = 1000,e = 8999;
int n;
vector<int> arr;//存储构造的所有回文串
int month[13] = { 0, 31,28,31,30,31,30,31,31,30,31,30,31 };
bool check(int yy,int mm,int dd);
void init();
int upper_bound(int key);
int ababbaba(int index);
int main()
{
    int n;
    cin>>n;
    init();

    int index = upper_bound(n);
    cout<<arr[index]<<endl;

    index = ababbaba(index);
    cout<<arr[index];

    return 0;
}

bool check(int yy,int mm,int dd)
{//判断日期是否合法

    if(mm>=1 && mm <=12)
    {
        if((yy%400==0) || (yy%4 == 0 && yy %100!=0))
        {
            month[2] = 29;
        }
        if(month[mm]>=dd)
            return true;
        else
            return false;
    }
    return false;
}
void init()
{//预处理回文日期
    for(int i=b;i<=e;i++)
    {
        string s = to_string(i);//转string

        for(int j=3;j>=0;j--)
        {
            s += s[j];
        }

        int mm = (s[4]-'0')*10+(s[5]-'0');//月
        int dd = (s[6]-'0')*10+(s[7]-'0');//日

        if(check(i,mm,dd))
        {
            int k = stoi(s);//转int
            arr.push_back(k);
        }

        month[2] = 28;

    }
}

int upper_bound(int key)
{
    int l,r,mid;
    l = 0,r = arr.size();
    while(l<=r)
    {
        mid = (l+r)>>1;

        if(arr[mid]>key)
            r = mid-1;
        else
            l = mid+1;
    }
    return l;
}
int ababbaba(int index)
{
    for(int i = index;i<arr.size();i++)
    {
        string s = to_string(arr[i]);

        if(s[0]==s[2] && s[1]== s[3])
            return i;
    }

    return 0;
}

试题H:子串分值和

【题目描述】

蓝桥杯2020第十一届C语言B组省赛习题题解_第6张图片

【题意分析】

现在还是有点搞不懂,到底为什么可以使用学长的那种方法,原理不太明白,还得再想想

【代码展示】

#include
#include
#include
#include
#include
#include

typedef long long ll;
using namespace std;

int main()
{
    string str;
    cin>>str;
    ll sum = 0;
    int que[27]={0};
    for(int i=0;i<str.length();i++)
    {
        que[str[i]-'a'] = i+1;
        for(int i=0;i<27;i++)
        {
            sum += que[i];
        }
    }
    cout<<sum<<endl;

    return 0;
}

试题I:平面切分

【题目描述】

蓝桥杯2020第十一届C语言B组省赛习题题解_第7张图片

【题意分析】

【代码展示】

#include
#include
#include
#include
#include
#include
//这部分代码来自于海铭学长,自己只是敲了一遍。还得多努力
typedef long long ll;
using namespace std;
map<int,map<int,int> > flag;//使用map标记是因为数据是非常大的,看数据会知道最大是99999,显然你用二位数组来存储,肯定开不了这么大的数组的
int q[1007][2];
int main()
{
    int n;
    cin>>n;
    int in = 0;
    int x,y;
    for(int i=0;i<n;i++)
    {
        scanf("%d %d",&x,&y);
        if(!flag[x][y])
        {
            flag[x][y] = 1;
            q[in][0] = x;
            q[in][1] = y;
            in ++;
        }
    }

    map<double ,map<double,double> >ma;
    int ans = 0;
    for(int i1 = 0;i1< in;i1++)
    {
        ma.clear();
        for(int i2 = i1+1;i2<in;i2++)
        {
            if(q[i1][0]==q[i2][0])
                continue;
            double x = (q[i1][1]-q[i2][1])/(double)(q[i2][0]-q[i1][0]);
            double y = q[i1][0]*x + q[i1][1];
            if(!ma[x][y])
            {
                ma[x][y] = 1;
                ans ++;
            }
        }
    }
    cout<<ans + in + 1<<endl;
}


试题J:字串排序

【题目描述】

蓝桥杯2020第十一届C语言B组省赛习题题解_第8张图片蓝桥杯2020第十一届C语言B组省赛习题题解_第9张图片

还不会,待补充。。。。。。

你可能感兴趣的:(学习经验分享,算法)