2022年第十三届蓝桥杯真题省赛解析(详细思路+代码实现)

目录

试题 A: 九进制转十进制

试题 B: 顺子日期

试题 C: 刷题统计

试题 D: 修剪灌木

试题 E: X 进制减法

试题 F: 统计子矩阵

试题 G: 积木画

试题 H: 扫雷

试题 I: 李白打酒加强版

试题 J: 砍竹子


试题 A: 九进制转十进制

 思路:2 * 9 * 9 * 9 + 0 * 9 * 9 + 2 * 9 + 2 * 1 = 1478

试题 B: 顺子日期

 思路:枚举字符串

试题 C: 刷题统计

 思路:数据范围10的18次方,如果暴力枚举一定会TLE,将7天看成一个整体,res =  n/7*x + n%7

代码实现

#include<iostream>

using namespace std;

typedef long long LL;

int main()
{
    LL a,b,n;
    scanf("%lld%lld%lld", &a, &b, &n);
    
    LL res = 0;
    LL s = 5*a + 2*b;
    res += (n/s)*7;
    n %= s;
    while( n > 0 )
    {
        if( res % 7 < 5) n -= a;
        else n -= b;
        res ++;
    }
    printf("%lld\n", res);
    return 0;
}

试题 D: 修剪灌木

思路:每颗灌木有两种极限长度,分别为从左边开始剪,和从右边开始剪,由题意知道,每天傍晚

才剪,所以,在剪之前的长度为,第一个位置,或最后一个位置,与该位置的差值*2;

代码如下

#include<bits/stdc++.h>

using namespace std;

int main()
{
    int n;
    scanf("%d", &n);
    
    for(int i=1;i<=n;i++)
        printf("%d\n", 2*max(n-i,i-1));
    
    return 0;
}

试题 E: X 进制减法

样例说明: 这个题难点在于读题(作为读了一个小时的过来人来说,,,),样例为321 转化为 65,65 = 3 * 10 * 2 * 1 + 2 * 2 * 1 + 1 * 1;可知,每个数位上的数字的含义为,该数字 * 低位的每一位的进制。同样,94 = 9 * 5 * 2 + 2 * 2 * 1 + 0 * 1;

思路:long long 保存结果,秦九韶算法得到答案

秦九韶算法解释:123 = ( ( ( 0 + 1 ) * 10) +2)*10 + 3;

详细介绍请移步这边博客秦九韶算法

代码如下

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <vector>

using namespace std;

typedef long long LL;

const int mod = 1000000007, N = 2000010;

int n;
int n1, n2;
LL a[N], b[N], x[N], mul[N];
LL res = 0;

int main()
{
    scanf("%d", &n);
    
    scanf("%d", &n1);
    for(int i = n1; i; i -- )
        scanf("%lld", &a[i]);

    scanf("%d", &n2);
    for(int i = n2; i; i -- )
        scanf("%lld", &b[i]);
    
    LL res = 0;
    for(int i = max(n1, n2); i; i -- )
        res = (res * max({(LL)2, a[i] + 1, b[i] + 1}) + a[i] - b[i]) % mod;
    
    printf("%lld\n", res);
    
    return 0;
}

试题 F: 统计子矩阵

 

 思路:二位前缀和板子题???,不对,蓝桥不会这么sha,hh,

暴力思路:四重循环;但,观察数据,N <= 500,暴力的话,500的4次方 = 62,500,000,000,必定TLE,但有一部分数据可以过,大概暴力可以过10分左右,,

AC思路:将四个数,化为三个数,枚举3次,可以过!

将每一列的数据求前缀和,双重循环枚举任何两行之间的数据,确定区间上下边界;用双指针算法来确定每一个横向区间的端点值 [ l, r ] 使 res += r - l + 1;long long 输出 res

代码如下

暴力代码:

#include <iostream>
#include <algorithm>
#include <cstdio>


using namespace std;

typedef long long LL;

const int N = 510;

int n, m;
LL k;
LL a[N][N], s[N][N];

int main()
{
    scanf("%d%d%lld", &n, &m, &k);
    
    for(int i = 1; i <= n; i ++ )
        for(int j = 1; j <= m; j ++ )
            scanf("%lld", &a[i][j]);
            
    for(int i = 1; i <= n; i ++ )
        for(int j = 1; j <= m; j ++ )
            s[i][j] = s[i-1][j] + s[i][j-1] - s[i-1][j-1] + a[i][j];
    
    LL res = 0;
    for(int i1 = 1; i1 <= n; i1 ++ )
        for(int j1 = 1; j1 <= m; j1 ++ )
            for(int i2 = i1; i2 <= n; i2 ++ )
                for(int j2 = j1; j2 <= m; j2 ++ )
                {
                    LL x = s[i2][j2] - s[i1 - 1][j2] - s[i2][j1 - 1] + s[i1 - 1][j1 - 1];
                    if(x <= k) res ++;
                }
                
    printf("%lld\n", res);
            
    return 0;
}

AC代码:

#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 510;

int n, m;
LL k;
int s[N][N];

int main()
{
    scanf("%d%d%lld", &n, &m, &k);
    
    for(int i = 1; i <= n; i ++ )
        for(int j = 1; j <= m; j ++ )
        {
            scanf("%d", &s[i][j]);
            s[i][j] += s[i-1][j];
        }
    
    LL res = 0;
    for(int i = 1; i <= n; i ++ )
    {
        for(int j = i; j <= n; j ++ )
        {
            for(int l = 1, r = 1, sum = 0; r <= m; r ++ )
            {
                sum += s[j][r] - s[i-1][r];
                while(sum > k)
                {
                    sum -= s[j][l] - s[i-1][l];
                    l ++;
                }
                res += r - l + 1;
            }
        }
    }
    
    printf("%lld\n", res);
    
    return 0;
}

试题 G: 积木画

积木画

思路:

  • 状态压缩 DP,蒙德里安的梦想的简化版
  • 可以手推状态转移

代码如下:

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

const int N = 1e7 + 10, mod = 1e9 + 7;

int n, m;

// 0 0
// 0 0

// 集合:所有 第 i - 1 列已经装满,开始装第 i 层,且第 i 列的状态为 j 的方案
// 属性:数量
int f[2][4]; // 滚动数组

int g[4][4] = {
    {1, 1, 1, 1},
    {0, 0, 1, 1},
    {0, 1, 0, 1},
    {1, 0, 0, 0},
};

int main()
{
    cin >> n;
    
    f[1][0] = 1;
    
    for (int i = 1; i <= n; i ++ )
    {
        memset(f[i + 1 & 1], 0, sizeof f[0]);
        for (int j = 0; j < 4; j ++ )
            for (int k = 0; k < 4; k ++ )
                if(g[j][k])
                    f[i + 1 & 1][k] = (f[i + 1 & 1][k] + f[i & 1][j]) % mod;
    }
    cout << f[n + 1 & 1][0] << endl;
    
    return 0;
}

试题 H: 扫雷

试题 I: 李白打酒加强版

试题 J: 砍竹子

  • 7
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

AC自动寄

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

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

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

打赏作者

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

抵扣说明:

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

余额充值