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

Problem A 空间

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

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

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

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

code:

#include
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直线

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

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

error code:

#include
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
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货物摆放

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

这个题没有办法,暴力吧,纯暴力还不行,必须优化!
我的思路:
由于要拆解成因子,拆解的三个因子(设为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
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路径

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

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

#include
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时间显示

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

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

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

#include
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砝码称重

2021年第十二届蓝桥杯省赛B组(C/C++)个人题解_第8张图片
2021年第十二届蓝桥杯省赛B组(C/C++)个人题解_第9张图片

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

#include
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
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杨辉三角

2021年第十二届蓝桥杯省赛B组(C/C++)个人题解_第10张图片
2021年第十二届蓝桥杯省赛B组(C/C++)个人题解_第11张图片

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

#include
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双向排序

2021年第十二届蓝桥杯省赛B组(C/C++)个人题解_第12张图片
2021年第十二届蓝桥杯省赛B组(C/C++)个人题解_第13张图片

我的思路:
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
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括号序列

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

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

#include
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,,,暴力,,,骗分,,,

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

你可能感兴趣的:(蓝桥杯)