2021年第十二届蓝桥杯省赛B组(C/C++)个人题解

Problem A 空间

在这里插入图片描述

计组基础题:256MB=256 * 2^20 * 8 位
所以存放32位元素可以存放 256 * 1024 * 1024 * 8 / 32
ans: 67108864
送分题
Problem B 卡片

在这里插入图片描述

题目就是说0—9一共9种卡片,如果,每个3张可以排到10,那如果每个2021张可以排到多少?
我的思路:
第一遍做这个题时写了个3182,后来检查时又仔细读了一遍题发现不对,最后应该输出3181,差点儿错了,,,

code:

#include<bits/stdc++.h>
using namespace std;
int num[10];

int del(int n)
{
    while(n){
        int index=n%10;
        if(num[index]==0)return 0;
        else num[index]--;
        n/=10;
    }
    return 1;
}

int main()
{
    for(int i=0;i<=9;i++){
        num[i]=2021;
    }

    int n=1;
    while(1){
        int ff=del(n);
        if(ff==0)break;
        else n++;
    }
    printf("%d",n-1);
    return 0;
}

ans:3181

Problem C直线

在这里插入图片描述

我的思路:
这题我错了,
我用的set<pair<double,double> > line_set;存放k与b,最后输出20+21+line_set.size(),然后,,,然后就错了,,,double精度导致错误;

error code:

#include<bits/stdc++.h>
using namespace std;
set<pair<double,double> > line_set;

int main()
{
    int x1,y1,x2,y2;
    for(x1=0;x1<20;x1++){
        for(y1=0;y1<21;y1++){
            for(x2=0;x2<20;x2++){
                for(y2=0;y2<21;y2++){
                    if(x1!=x2&&y1!=y2){
                        double k=(y2-y1)*1.0/(x2-x1);
                        double b=y2-k*x2;

                        pair<double ,double > newline;
                        newline.first=k;
                        newline.second=b;
                        line_set.insert(newline);
                    }
                }
            }
        }
    }
    printf("%d",line_set.size()+20+21);
    return 0;
}

这样算出来是47753(error ans),知乎上有人说是40257,哎,蓝瘦~
贴一下正确解:

#include<bits/stdc++.h>
using namespace std;
set<pair<double,double> > line_set;

int main()
{
    int x1,y1,x2,y2;
    for(x1=0;x1<20;x1++){
        for(y1=0;y1<21;y1++){
            for(x2=0;x2<20;x2++){
                for(y2=0;y2<21;y2++){
                    if(x1!=x2&&y1!=y2){
                        double k=(y2-y1)*1.0/(x2-x1);
                        double b=(y2*(x2-x1)-(y2-y1)*x2)*1.0/(x2-x1);
                        //重点!这么写可以规避掉double炸精度问题

                        pair<double ,double> newline;
                        newline.first=k;
                        newline.second=b;
                        line_set.insert(newline);
                    }
                }
            }
        }
    }
    printf("%d",line_set.size()+20+21);
    return 0;
}
//40257

Problem D货物摆放

在这里插入图片描述

这个题没有办法,暴力吧,纯暴力还不行,必须优化!
我的思路:
由于要拆解成因子,拆解的三个因子(设为a,b,c),把a,b,c放到一个集合里s;
始终要a<=b<=c(不然超时!)
如果s.size()==1,ans+=1;//abc三者相等,为一种情况
如果s.size()==2,ans+=3;//abc三个有两个相等,则独立的哪个有三种放法
如果s.size()==3,ans+=6;//abc互不相等,全排列3 * 2 *1种

循环一定要两层,不要三层,必须使用sqrt降低复杂度

code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    ll n=2021041820210418;
    ll en1=sqrt(n);
    ll ans=0;
    for(ll a=1;a<=en1;a++){
        if(n%a==0){
            ll nn=n/a;
            ll en2=sqrt(nn);
            for(ll b=1;b<=en2;b++){
                if(nn%b==0){
                    ll c=nn/b;
                    if(c>=b&&b>=a){
                        set<int> s;
                        s.insert(a);
                        s.insert(b);
                        s.insert(c);

                        if(s.size()==1)ans++;
                        else if(s.size()==2)ans+=3;
                        else if(s.size()==3)ans+=6;
                    }
                }
            }
        }
    }
    printf("%lld",ans);
    return 0;
}

ans:2430
Problem E路径

在这里插入图片描述

我的思路:
dijkstra即可,然而呢,我写的dijkstra调试了半天也不对,气急败坏之下又用的Floyd,三层for循环,等了10秒左右总算是跑出来了,,,
code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define   INF   999999999
int gcd(int a,int b){
    if(b==0)return a;
    else return gcd(b,a%b);
}
int M[2022][2022];
int main(){
    for(int i=1;i<=2021;i++){
        for(int j=1;j<=2021;j++){
            if(i==j)M[i][j]=M[j][i]=0;
            else if(abs(i-j)>21)M[i][j]=M[j][i]=INF;
            else M[i][j]=M[j][i]=i*j/gcd(i,j);
        }
    }

    for(int i=1;i<=2021;i++){
        for(int j=i+1;j<=2021;j++){
            for(int k=i;k<=j;k++){
                if(M[i][k]!=INF&&M[k][j]!=INF&&(M[i][j]>M[i][k]+M[k][j])){
                    M[i][j]=M[j][i]=M[i][k]+M[k][j];
                }
            }
        }
    }
    printf("%lld",M[1][2021]);
    return 0;
}

ans:10266837

Problem F时间显示

在这里插入图片描述

在这里插入图片描述

题干说给出一个毫秒数,输出对应的hh:mm:ss
我的思路:
签到题
input_case1:
46800999
output_case1:
13:00:00
input_case2:
1618708103123
output_case2:
01:08:23
code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    ll n;
    scanf("%lld",&n);
    n/=1000;
    n%=(24*60*60);
    int ss=n%60;
    n/=60;
    int mm=n%60;
    n/=60;
    int hh=n%60;
    n/=60;
    printf("%02d:%02d:%02d",hh,mm,ss);
    return 0;
}

Problem G砝码称重

在这里插入图片描述
在这里插入图片描述

我的思路:
哎,万万没想到,第二个编程题直接来个dp,蓝桥杯啊,你变了啊,做往年的省赛b组题基本没遇到过dp,去年考了dp也只是在填空里考了,今年直接第二道编程考dp,哎,菜是原罪!
看了半天没思路,又看了看测试样例范围 50%的样例在1<=n<=15,果断dfs深搜骗分,,,
input_case:
3
1 4 6
output_case:
10
code:

#include<bits/stdc++.h>
using namespace std;

int n;
int w[102];
int flag[102];
set<int> ans;
int ff=0;
void dfs(int sum1,int sum2){
    if(sum1<sum2)return ;
    else{
        if(sum1>sum2){
            ans.insert(sum1-sum2);
        }
    }
    for(int i=1;i<=n;i++){
        if(!flag[i]){
            flag[i]=1;
            dfs(sum1+w[i],sum2);
            dfs(sum1,sum2+w[i]);
            flag[i]=0;
        }
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&w[i]);
    }
    dfs(0,0);
    printf("%d",ans.size());
    return 0;
}

贴一下正确解:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int dp[102][100002];

int main()
{
    int n;
    scanf("%d",&n);
    int w[n+1];
    ll sum=0;
    for(int i=1;i<=n;i++){
        scanf("%d",&w[i]);
        sum+=w[i];
    }

    for(int i=1;i<=n;i++){
        for(int j=1;j<=sum;j++){
            dp[i][j]=dp[i-1][j];
            if(dp[i][j]==0){
                if(w[i]>j)dp[i][j]=dp[i-1][w[i]-j];
                if(w[i]==j)dp[i][j]=1;
                if(w[i]<j)dp[i][j]=dp[i-1][j-w[i]];
            }
        }
    }

    ll ans=0;
    for(int i=1;i<=sum;i++){
        if(dp[n][i])ans++;
    }
    printf("%lld",ans);
    return 0;
}

Problem H杨辉三角

在这里插入图片描述
在这里插入图片描述

我的思路:
没思路,,暴力骗分,,
组合数学问题
input_case:
6
output_case:
13
code:

#include<bits/stdc++.h>
using namespace std;
int M[3001][3001];
int main(){

    int n;
    scanf("%d",&n);

    for(int i=1;i<=n+1&&i<=3000;i++){
        M[i][i]=1;
        M[i][1]=1;
    }

    for(int i=3;i<=n+1&&i<=3000;i++){
        for(int j=2;j<i;j++){
            M[i][j]=M[i-1][j]+M[i-1][j-1];
        }
    }
    int num=1;
    for(int i=1;i<=n+1&&i<=3000;i++){
        for(int j=1;j<=i;j++){
            if(M[i][j]==n){
                printf("%d",num);
                return 0;
            }else{
                num++;
            }
        }
    }
    return 0;
}

Problem I双向排序

在这里插入图片描述
在这里插入图片描述

我的思路:
sort骗分,
刚开始以为用sort连30%的测试点都过不了(毕竟快排的最坏时间复杂度是平方阶的!),后来看了一下别人博客了解到,sort还是很牛的,毕竟是c++封装好的排序函数,记得之前学快排的时候,快排有好几种优化方案,什么三点取中法,等等,c++里面的sort是优化到极致的快排,很好用;
! (~ _ ~;)
n=4000,m=4000是不超时的,sort至少可以骗50%的分数。
input_case:
3 3
0 3
1 2
0 2
output_case:
3 1 2

code:

#include<bits/stdc++.h>
using namespace std;

bool cmp1(int a,int b)//升序
{
    return a<b;
}

bool cmp2(int a,int b)//降序
{
    return a>b;
}

int main(){
    int n,m;
    scanf("%d %d",&n,&m);
    int a[n+1];
    for(int i=1;i<=n;i++){
        a[i]=i;
    }

    int op,index;
    for(int i=0;i<m;i++){
        scanf("%d %d",&op,&index);
        if(op==0){
            sort(a+1,a+index+1,cmp2);
        }else{
            sort(a+index,a+n+1,cmp1);
        }
    }
    for(int i=1;i<=n;i++){
        printf("%d",a[i]);
        if(i<n)printf(" ");
    }
    return 0;
}

Problem J括号序列

在这里插入图片描述

我的思路:
状压dp,蓝桥杯是真的变了,,,
又是dfs写的,骗分,,,
input_case:
((()
oupput_case:
5
code:

#include<bits/stdc++.h>
using namespace std;
string s;
set<string> e;
int addNum;
char c;

bool isok()
{
    stack<char> sta;
    for(int i=0;i<s.size();i++){
        if(s[i]=='('){
            sta.push(s[i]);
        }else{
            if(sta.empty()||sta.top()!='(')return false;
            else sta.pop();
        }
    }
    if(sta.empty())return true;
    else return false;
}

void dfs(int depth){
    if(depth==addNum){
        if(isok()){
            e.insert(s);
        }
    }else{
        for(int i=0;i<s.size();i++){
            s.insert(s.begin()+i,c);
            dfs(depth+1);
            s.erase(s.begin()+i,s.begin()+i+1);
        }
    }
}

int main()
{
    cin>>s;
    int left=0,right=0;
    for(int i=0;i<s.size();i++){
        if(s[i]=='(')left++;
        else right++;
    }
    if(left==right){
        printf("0");
        return 0;
    }else{
        if(left>right)c=')';
        else c='(';

        addNum=abs(left-right);
        dfs(0);
        printf("%d",e.size());
    }
    return 0;
}

总结:
填空对了4道,编程题只有第一个保证ac,其它4个均是dfs,,,暴力,,,骗分,,,

第一次参加蓝桥杯就突然难了,哎,菜是原罪啊!蓝桥杯是真的变了,加入了蝉联出题就硬气了,这几年来蓝桥杯也一直为人诟病,今年突然难了其实也是好事吧,希望蓝桥杯发展的越来越好吧。

  • 124
    点赞
  • 475
    收藏
    觉得还不错? 一键收藏
  • 41
    评论
由于2021蓝桥杯Java B比赛尚未开始,因此没有实际的比赛题目和答案。以下是蓝桥杯历Java B比赛的题目范例,供参考: 1. 企业进销存系统 题目描述: 某企业需要实现一个进销存系统,以管理商品的进销存情况。系统需要支持以下功能: - 添加商品:向系统中添加新的商品 - 添加进货记录:向指定商品的进货记录中添加一条新的记录 - 添加销售记录:向指定商品的销售记录中添加一条新的记录 - 查询商品信息:根据商品编号查询商品的基本信息以及进货和销售记录 要求: 1. 商品基本信息包括:商品编号、商品名称、商品单价、库存数量等。 2. 进货记录和销售记录包括:日期、数量、进价/售价等信息。 3. 数据可以存储在本地文件中,也可以存储在数据库中。 4. 系统需要提供界面来支持用户操作。 实现提示: 可以使用Java GUI框架(例如JavaFX、Swing等)来实现系统的界面,使用Java IO或者JDBC来读写数据,可以设计数据访问层来管理数据操作。 2. 田忌赛马问题 题目描述: 有两个马车队,分别由田忌和齐王率领。他们需要比赛,决定采用同样的策略:每次比较两个队列中最慢的马,让速度更快的马和对方的最慢马比赛。如果田忌的马胜出,则获得1分,否则齐王获得1分。比赛结束后,获得更多分数的一方获胜。 某一天,田忌和齐王又要比赛了,请你设计一个Java程序来帮助田忌制定赛马策略,使田忌能获得胜利(限制条件:田忌不能使用所有的快马)。 要求: 1. 输入格式:首先输入队伍中马的数量n(1<=n<=100),然后分别输入田忌和齐王掌握的马的速度(按从快到慢的顺序递增),共计n个数字。 2. 输出格式:输出田忌获胜的方案,每行一,用“缓马”代表慢马,用“快马”代表快马。 3. 赛马策略: - 同级对决:每次都让田忌的最慢的马和齐王的最慢马比较。 - 待发配对:若田忌的最慢的马比齐王的最慢马快,则让田忌的最快的马与齐王的最慢的马比较,否则就让田忌最慢的马和齐王最快的马比较。 实现提示: 此题可以使用贪心算法来实现,将田忌和齐王的队伍按照速度从快到慢排序,然后从前往后遍历,当田忌最慢的马速度大于齐王最慢马速度时,就让它和齐王最慢的马比较;否则让它和齐王最快的马比较。
评论 41
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值