2021第十二届蓝桥杯C++B组省赛第二场个人题解(大部分)

C++省赛B组个人题解(部分

目录

  • 试题A:空间
  • 试题B:卡片
  • 试题C:直线
  • 试题D:货物摆放
  • 试题E:路径
  • 试题F:时间显示
  • 试题G:砝码称重
  • 试题H:杨辉三角形
  • 试题I:双向排序
  • 试题J:括号序列
  • 个人总结:

试题A:空间

题目
2021第十二届蓝桥杯C++B组省赛第二场个人题解(大部分)_第1张图片

答案:67108864

分析
计算机组成原理题,一上来就栽跟头了。。。
1byte=8bits,Bit意为"位"或"比特",是计算机运算的基础;
Byte意为"字节",是计算机文件大小的基本计算单位;
8个二进制位构成1个"字节(Byte)",即1Byte=8bit
所以1个32位二进制数占4个Byte。
答案为
2021第十二届蓝桥杯C++B组省赛第二场个人题解(大部分)_第2张图片

试题B:卡片

题目
2021第十二届蓝桥杯C++B组省赛第二场个人题解(大部分)_第3张图片

答案:3181

分析
打卡题

#include 
using namespace std;
int a[10];
bool ok(int x)  //每个数消耗卡片
{
     
    while(x)
    {
     
        int temp = x % 10;
        if(a[temp])
        {
     
            a[temp]--;
            x /= 10;
        }
        else
            return 0;
    }
    return 1;
}
int main()
{
     
    fill(a, a + 10, 2021); //总共的卡片数
    for (int i = 1;; i++)
    {
     
        if(ok(i))
            continue;
        else
        {
     
            cout << i - 1;
            break;
        }
    }
    return 0;
}

试题C:直线

题目
2021第十二届蓝桥杯C++B组省赛第二场个人题解(大部分)_第4张图片

答案:41255(不确定)

分析
一看像个数学题,可是又推不出数学公式,然后就分三种情况讨论,哈希统计个数,测试样例和自己测试的小样例都过了,不过好像数据大了,double精度不够用,不知道对不对
1.平行于y轴 直线表达式为x=???
2.平行于x轴 直线表达式为y=???
3.普通一次函数 直线表达式为y=kx+b

#include 
using namespace std;
set<pair<double, double> > ss;//普通的直线
set<double> dx,dy;//两种特殊的直线
struct point
{
     
    double x, y;
};
void solve(point a,point b)
{
     
    if(a.x==b.x)    //平行于y轴
        dx.insert(a.x);
    else if(a.y==b.y)    //平行于x轴
        dy.insert(a.y);
    else    //计算表达式y=kx+bb
    {
     
        double k = (b.y - a.y) / (b.x - a.x);
        double bb = a.y - k * a.x;
        ss.insert(pair<double, double>(k, bb));
    }
}
int main()
{
     
    
    vector<point> v;
    for (int i = 0; i <= 19;i++)
    {
     
        for (int j = 0; j <= 20;j++)
        {
     
            point temp = {
     i * 1.0, j * 1.0};//转换为double
            v.push_back(temp);
        }
    }
    int len = v.size();
    for (int i = 0; i < len;i++)    //枚举所有的直线
    {
     
        for (int j = i + 1; j < len;j++)
        {
     
            solve(v[i], v[j]);
        }
    }
    cout << dx.size() + dy.size() + ss.size();  //三种直线集合个数求和
    return 0;
}

试题D:货物摆放

题目
2021第十二届蓝桥杯C++B组省赛第二场个人题解(大部分)_第5张图片

答案:2430

分析
首先,这个数非常大,达到了1e16级别,所以直接枚举,是不可能的
题目要求3个数相乘,得到这个数,因此,这三个数必定是这个数的因子,所以我想到了首先求出这个数的所有因子。因子数求法可以参考我的文章求因子数
然后求因子复杂度只需要sqrt(n)级别,也就是1e8,这个复杂度是可以接受的,最后在求到的因字数中,枚举三个数的乘积是否等于这个数

#include 
using namespace std;
typedef long long ll;
const ll n = 2021041820210418;
int main()
{
     
    set<ll> fac; //存放因子
    for (int i = 1; i <= sqrt(n);i++)
    {
     
        if(n%i==0)
        {
     
            fac.insert(i);
            fac.insert(n / i);
        }
    }
    vector<ll> v;  //  转存到数组里面,方便操作
    for(ll e:fac)   //foreach遍历
        v.push_back(e);
    int len = v.size();
    int cnt = 0;
    for (int i = 0; i < len;i++) //三重循环,枚举因子数乘积
        for (int j = 0; j < len;j++)
            for (int k = 0; k < len;k++)
            {
     
                if(v[i]*v[j]*v[k]==n)
                    cnt++;
            }
    cout << cnt;
    return 0;
}

试题E:路径

题目
2021第十二届蓝桥杯C++B组省赛第二场个人题解(大部分)_第6张图片

答案:10266837

分析
一开始没看懂题,跳过去了,最后20分钟才想起思路,寒假刷pat的题库终于在蓝桥起作用了,有惊无险。。。
考点就是求最小公倍数和最短路径算法dijstra
推荐柳神的最短路径算法模板dfs最短路径
不过此题也可以用dp做,过程貌似更简洁

#include 
using namespace std;
typedef long long ll;
const ll inf = 1e12;
int vis[2050];
ll e[2050][2050], dis[2050];
ll gcd(ll a,ll b)   //求最大公因数
{
     
    return a % b == 0 ? b : gcd(b, a % b);
}
ll lcm(ll a,ll b)	//求最小公倍数
{
     
    return a * b / gcd(a, b);
}
int main()
{
     
    fill(dis, dis + 2050, inf);
    fill(e[0], e[0] + 2050 * 2050, inf);
    for (int i = 1; i <= 2021;i++)
    {
     
        for (int j = 1; j <= 21;j++)    //21步以内有效
        {
     
            int k = i + j;  //i为起点,k为终点
            if(k>2021)
                break;
            e[i][k] = e[k][i] = lcm(i, k);
        }   
    }
    dis[1] = 0;
    //最短路径模板  dijstra算法
    for (int i = 1; i <= 2021;i++)
    {
     
        ll u = -1, minn = inf;
        for (int j = 1; j <= 2021;j++)//找到起点
        {
     
            if(!vis[j]&&dis[j]<minn)
            {
     
                minn = dis[j];
                u = j;
            }
        }
        if(u==-1)
            break;
        vis[u] = 1;
        for (int v = 1; v <= 2021;v++)
        {
     
            if(!vis[v])
                dis[v] = min(dis[v], e[u][v] + dis[u]);
        }
    }
    cout << dis[2021];
    return 0;
}

试题F:时间显示

题目
2021第十二届蓝桥杯C++B组省赛第二场个人题解(大部分)_第7张图片

分析
打卡题,注意题目说法,毫秒直接舍去

#include 
typedef long long ll;
using namespace std;
int main()
{
     
    ll n;
    int mod = 3600 * 24;//一天的秒数
    cin >> n;
    n /= 1000;	//舍去毫秒
    n %= mod;
    int h = (n / 3600) % 24;
    int m = ((n % 3600)/60)%60;
    int s = n % 60;
    printf("%02d:%02d:%02d", h, m, s);
    return 0;
}

试题G:砝码称重

题目
2021第十二届蓝桥杯C++B组省赛第二场个人题解(大部分)_第8张图片

分析
dp题,看了5分钟没思路,跑路了

试题H:杨辉三角形

题目
2021第十二届蓝桥杯C++B组省赛第二场个人题解(大部分)_第9张图片

分析
看到这题心就凉了,可能有数学公式,但是考试时我肯定推不出来,就直接暴力模拟了,只开了一维数组,每开辟新的一行,就复制一份,判断每个元素是否等于n
(大数据超时):

#include 
using namespace std;
typedef long long ll;
vector<ll> a;
int main()
{
     
    ll n;
    cin >> n;
    ll cnt = 2;
    if (n == 1)
        cout << 1;
    else
    {
     
        a.push_back(1); //第二层
        a.push_back(1); 
        while (1)
        {
     
            cnt++; //第cnt层
            vector<ll> temp(a); //复制上一份
            for (ll i = 1; i < cnt - 1; i++)
            {
     
                temp[i] = a[i] + a[i - 1];
                if (temp[i] == n) //找到了这个数
                {
     
                    ll ans = cnt* (cnt - 1) / 2;
                    ans += (1 + i);
                    cout << ans;
                    return 0;
                }
            }
            temp.push_back(1);  //末尾元素
            a = temp;
        }
    }
    return 0;
}

试题I:双向排序

题目
2021第十二届蓝桥杯C++B组省赛第二场个人题解(大部分)_第10张图片

分析
直接一步步排序的,看上去太简单了,希望没有坑。

#include 
using namespace std;
typedef long long ll;
bool cmp(int a,int b)
{
     
    return a > b;
}
int main()
{
     
    int n, m;
    cin >> n >> m;
    int a[n];
    for (int i = 0; i < n;i++)
        a[i] = i + 1;
    for (int i = 0; i < m;i++)
    {
     
        int p, q;
        scanf("%d %d", &p, &q);
        if(p==0)
            sort(a, a + q,cmp);
        else
            sort(a + q - 1, a + n);
    }
    for (int i = 0; i < n;i++)
    {
     
        printf("%d", a[i]);
        if(i!=n-1)
            printf(" ");
    }
    return 0;
}

试题J:括号序列

题目
2021第十二届蓝桥杯C++B组省赛第二场个人题解(大部分)_第11张图片

分析
dp,白给。输出了s长度等于1~3的答案,希望能混到测试样例。

个人总结:

第二次参加蓝桥杯(B组省赛),今年题明显比往年难了很多,考的知识面也覆盖广了。难道是蓝桥杯排名不断上升,题也跟着变了味?不过省赛总体思路还是暴力加一些基本的数学知识。这次第一题完全就是考概念。。。第一题就白给了,确实蛮打击人的。最后一次参加蓝桥了,希望不会白给。
2021第十二届蓝桥杯C++B组省赛第二场个人题解(大部分)_第12张图片

你可能感兴趣的:(LANQIAO,数据结构,算法,图论,动态规划)