2021年第十二届蓝桥杯省赛C/C++B组题解总结

前几天(2021.4.18)刚刚比完了2021年第十二届蓝桥杯省赛,本人参加的是软件组C++B组的比赛,本文包括了这一届C++B组的题目以及部分题解、感悟和总结。

试题A.空间

在这里插入图片描述
考查计算机基础知识,一字节等于8位,1MB=220B
答案:67108864

256*2^20/4

试题B.卡片

在这里插入图片描述
一道模拟题,注意题目要求求出能够拼到多少,而不是求不够拼出多少,最后结果要减1
答案:3181

#include <iostream>

using namespace std;
int cnt[15];

int main()
{
    for(int i=0;i<=9;i++) cnt[i]=2021;
    int i;
    for(i=1;;i++){
        int t=i;
        while(t){
            if(cnt[t%10]==0){
                cout<<i-1;
                return 0;
            }
            cnt[t%10]--;
            t/=10;
        }
    }
    return 0;
}

试题C.直线

在这里插入图片描述
根据直线两点式推导转换成直线一般方程ax+by+c=0(见下图)这样就不用考虑斜率是否存在、避免除法的困扰了,通过除以公约数使a,b,c互质,放入set去重就行了,但是要重载操作符。
在这里插入图片描述

答案:40257

#include<iostream>
#include<cmath>
#include<set>
using namespace std;
struct node{//点
    int x,y;
}p[1000];
struct line{//直线
    int a,b,c;//直线一般方程的系数
    bool operator<(const line &p) const {
        if (a == p.a) return b == p.b ? c < p.c : b < p.b;
        return a < p.a;
    }
    bool operator==(const line &p) const {
        return a == p.a && b == p.b && c == p.c;
    }
};
int cnt;
set<line> se;
int gcd(int a,int b){
    return b==0?a:gcd(b,a%b);
}
int gcdd(int a,int b,int c){
    return gcd(gcd(a,b),gcd(b,c));
}
int main()
{
    int n=20,m=21;
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            p[++cnt]={i,j};
    for(int i=1;i<=cnt;i++){
        for(int j=i+1;j<=cnt;j++){
            int a=p[i].y-p[j].y;//系数
            int b=p[j].x-p[i].x;
            int c=p[i].y * (p[i].x-p[j].x)- p[i].x *(p[i].y-p[j].y);
            int t=gcdd(fabs(a),fabs(b),fabs(c));
            se.insert({a/t,b/t,c/t});
        }

    }
    cout<<se.size();
    return 0;
}

试题D.货物摆放

在这里插入图片描述
题目给的数很大,如果直接暴力两重循环会超时。转换思路,把n所有的约数求出来,发现 2021041820210418只有128个约数,然后对这128个约数暴力枚举两重循环,计算出结果。可惜这题比赛的时候思路歪了想错了。
答案:2430

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
LL yue[101000],cnt;

int main()
{
    LL n=2021041820210418;
    for(LL i=1;i<=n/i;i++){
        if(n%i==0){
            yue[++cnt]=i;
            if(i*i!=n)
                yue[++cnt]=n/i;
        }
    }
    //sort(yue+1,yue+cnt+1);
    //for(int i=1;i<=cnt;i++)cout<<yue[i]<<" ";
    //cout<<cnt;
    int ans=0;
    for(int i=1;i<=cnt;i++){
        for(int j=1;j<=cnt;j++){
            if(n%(yue[i]*yue[j])==0)
                ans++;
        }
    }
    cout<<ans;
    return 0;
}

试题E.路径

在这里插入图片描述
最短路径模版题,dijkstra跑一遍就行了。比赛的时候太赶时间了做完就直接把答案交上去了最后还忘记检查,太懊悔了,比赛结束发现我交的答案竟然是0x3f3f3f3f,我TM直接心态崩了。大家做完一定要好好检查!!!
答案:10266837

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int N=2510;
int g[N][N],dist[N],st[N];
int n=2021;
int gcd(int a, int b)
{
    return b ? gcd(b, a % b) : a;
}
int lcm(int a,int b){
    return a*b/gcd(a,b);
}
int dijkstra(){
    memset(dist,0x3f,sizeof dist);
    dist[1]=0;

    for(int i=1;i<=n;i++){
        int t=-1;
        for(int j=1;j<=n;j++){
            if(!st[j] && (t==-1 || dist[j]<dist[t]))
                t=j;
        }
        st[t]=1;
        for(int j=1;j<=n;j++){
                dist[j]=min(dist[j],dist[t]+g[t][j]);
        }
    }
    return dist[n];
}
int main(){
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
            if(i!=j){
                if(fabs(i-j)<=21){
                    g[i][j]=lcm(i,j);
                    g[j][i]=lcm(i,j);
                }
                else{
                    g[i][j]=0x3f3f3f3f;
                    g[j][i]=0x3f3f3f3f;
                }
            }
        }
    cout<<dijkstra();
    //cout<<0x3f3f3f3f;
    return 0;
}

试题F.时间显示

在这里插入图片描述

【样例输入 1】
46800999
【样例输出 1】
13:00:00
【样例输入 2】
1618708103123
【样例输出 2】
01:08:23
【评测用例规模与约定】
对于所有评测用例,给定的时间为不超过 1018 的正整数。

这算是一道相对比较简单的题了,也是唯一完整做出来的了,除法取模搞定,注意要用longlong。

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long LL;

int main()
{
    LL n;
    cin>>n;
    n/=1000;
    int h=n/3600%24;
    n=n%3600;
    int m=n/60%60;
    n=n%60;
    int s=n%60;
    printf("%02d:%02d:%02d",h,m,s);
    return 0;
}

试题G.砝码称重

在这里插入图片描述

【样例输入】
3
1 4 6
【样例输出】
10
【样例说明】
能称出的 10 种重量是:1、2、3、4、5、6、7、9、10、11。
1 = 1;
2 = 6 6 4 (天平一边放 6,另一边放 4);
3 = 4 1;
4 = 4;
5 = 6 1;
6 = 6;
7 = 1 + 6;
9 = 4 + 6 1;
10 = 4 + 6;
11 = 1 + 4 + 6。

【评测用例规模与约定】
对于 50% 的评测用例,1 ≤ N ≤ 15。
对于所有评测用例,1 ≤ N ≤ 100,N 个砝码总重不超过 100000。

嗯?不对劲哦,第二题就不会了,01背包?太菜了想不明白。


后补:闫氏dp分析法
在这里插入图片描述

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 110, M = 2e5 + 10;
int n,m;//m记录最大重量
int a[N];
bool dp[N][M];//dp[i][j]表示前i个砝码,称出j的集合,值为bool值,能称出j就true
//砝码称重
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i],m+=a[i];
    dp[0][0]=true;
    
    for (int i = 1; i <= n;i++)//前i个
        for (int j = 0; j <=m;j++)//称出j
            dp[i][j]=dp[i-1][j]||dp[i-1][j+a[i]]||dp[i-1][abs(j-a[i])];
            //只要有一种情况为真,那么dp[i][j]就真
    int ans=0;
    for(int i=1;i<=m;i++)
        if(dp[n][i])
            ans++;
    cout<<ans;
    return 0;
}

试题H.杨辉三角形

在这里插入图片描述

【样例输入】
6
【样例输出】
13
【评测用例规模与约定】
对于 20% 的评测用例,1 ≤ N ≤ 10;
对于所有评测用例,1 ≤ N ≤ 1000000000。

这数据开的也太大了吧,109次方,没办法了暴力前十个骗分。

试题I.双向排序

在这里插入图片描述

【样例输入】
3 3
0 3
1 2
0 2
【样例输出】
3 1 2
【样例说明】
原数列为 (1, 2, 3)。 第 1 步后为 (3, 2, 1)。 第 2 步后为 (3, 1, 2)。 第 3 步后为 (3, 1, 2)。与第 2 步操作后相同,因为前两个数已经是降序了。

【评测用例规模与约定】
对于 30% 的评测用例,n, m ≤ 1000;
对于 60% 的评测用例,n, m ≤ 5000;
对于所有评测用例,1 ≤ n, m ≤ 100000,0 ≤ ai ≤ 1,1 ≤ bi ≤ n。

上来直接用sort,时间复杂度O(mnlogn),一半分应该能拿到

#include<iostream>
#include<algorithm>
using namespace std;
int a[101000];

int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)a[i]=i;
    while(m--){
        int p,q;
        cin>>p>>q;
        if(p==0){
           sort(a+1,a+q+1,greater<int>());
        }else{
            sort(a+q,a+n+1);
        }
    }
    for(int i=1;i<=n;i++) cout<<a[i]<<" ";
    return 0;
}

yxc讲解:双向排序

试题J.括号序列

在这里插入图片描述

【样例输入】
((()
【样例输出】
5
【评测用例规模与约定】
对于 40% 的评测用例,|s| ≤ 200。
对于所有评测用例,1 ≤ |s| ≤ 5000。

好像也是用dp,不会做
yxc讲解:括号序列

总结

这次比赛感觉比想象的难一点,编程第二题就涉及了DP,做过以往的题目不会像今年直接编程第二题就无从下手,DP也只会几个经典的模版题,属实想不到,括号那题好像也是DP,真没法做,而且这一块练的也少新的背景根本想不到,更别说列出转移方程。最可气的还是路径那题,标准最短路径模版题,竟然拿不到分!!还是怪自己太粗心、不检查。总得来说虽然这次蓝桥杯拿不到好成绩,有点小遗憾,但是总归在准备过程中还是学到了不少东西。

评论 37
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weiambt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值