第十三届蓝桥杯b组题目讲解

本文介绍了多个编程题目,包括修建灌木、修剪灌木、X进制减法、统计子矩阵、积木画、扫雷、李白打酒加强版和砍竹子。每个题目都提供了详细的解题代码,涵盖了矩阵操作、动态规划、搜索算法和数学计算等核心算法概念,旨在提升读者的编程和算法解决能力。
摘要由CSDN通过智能技术生成

刷题记录

代码在4.15号更新

刷题统计题目链接

代码

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

using namespace std;
typedef long long LL;

int main(){
    LL a, b, n; cin >> a >> b >> n;
    LL x = 5 * a + 2 * b;
    LL zh = n / x;
    LL da = zh * 7;
    n = n % x;
    LL d[7] = {a, a, a, a, a, b, b};
    for (int i = 0; i < 7; i ++ ){
        if(n <= 0) break;
        n -= d[i];
        da ++;
    }
    cout << da << endl;
    return 0;
}

修建灌木

在这里插入图片描述
在这里插入图片描述
修剪灌木题目链接

代码

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

using namespace std;

int main(){
    int n; cin >> n;
    for (int i = 1; i <= n; i ++ ){
        cout << max(i - 1, n - i) * 2 << endl;
    }
    return 0;
}

X进制减法

在这里插入图片描述
在这里插入图片描述
X进制题目链接
在这里插入图片描述

代码

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

using namespace std;
typedef long long LL;
const int N = 1e5 + 10, mod = 1e9 + 7;

int a[N], b[N];
int m1, m2;

int main(){
    int n; cin >> n;
    cin >> m1;
    for (int i = m1 - 1; i >= 0; i -- ) cin >> a[i];
    cin >> m2;
    for (int i = m2 - 1; i >= 0; i -- ) cin >> b[i];
    int m = max(m1, m2); //高位补0
    //秦九韶算法
    int ans = 0;
    for (int i = m - 1; i >= 0; i -- ){
        ans = (ans * (LL)max({a[i] + 1, b[i] + 1, 2}) + (a[i] - b[i])) % mod;
    }
    cout << ans << endl;
    return 0;
}

统计子矩阵

在这里插入图片描述
在这里插入图片描述
统计子矩阵题目链接

代码1

矩阵前缀和

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

using namespace std;
typedef long long LL;
const int N = 555;

int g[N][N];

int get(int x1, int y1, int x2, int y2){
    return g[x2][y2] - g[x2][y1 - 1] - g[x1 - 1][y2] + g[x1 - 1][y1 - 1];
}

int main(){
    int n, m, k; cin >> n >> m >> k;
    for (int i = 1; i <= n; i ++ ){
        for (int j = 1; j <= m; j ++ ){
            cin >> g[i][j];
            //计算前缀和
            g[i][j] += g[i - 1][j] + g[i][j - 1] - g[i - 1][j - 1];
        }
    }
    LL res = 0;
    //i, j枚举上界和下届, l, r枚举左界和右界
    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 ++ ){
                while(l <= r && get(i, l, j, r) > k) l ++;
                res += r - l + 1;
            }
        }
    }
    cout << res << endl;
    return 0;
}

代码2

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

using namespace std;
typedef long long LL;
const int N = 555;

int g[N][N];

int main(){
    int n, m, k; cin >> n >> m >> k;
    for (int i = 1; i <= n; i ++ ){
        for (int j = 1; j <= m; j ++ ){
            cin >> g[i][j];
            //计算每一列的前缀和
            //1 2 3 4           1 2 3 4 
            //5 6 7 8           6 8 10 12 
            //9 10 11 12        15 18 21 24 
            g[i][j] += g[i - 1][j];
        }
    }
    LL res = 0;
    //i, j枚举上界和下届, l, r枚举左界和右界
    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 += g[j][r] - g[i - 1][r];
                while(sum > k){
                    sum -= (g[j][l] - g[i - 1][l]);
                    l ++;
                }
                res += r - l + 1;
            }
        }
    }
    cout << res << endl;
    return 0;
}

积木画

在这里插入图片描述
在这里插入图片描述
积木画题目链接

代码

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

using namespace std;
int g[4][4] = {
    {1, 1, 1, 1},
    {0, 0, 1, 1},
    {0, 1, 0, 1},
    {1, 0, 0, 0},
};
const int N = 1e7 + 10, mod = 1e9 + 7;
int f[N][4];
//f[i][j]表示前i-1个列都已经填满,并且第i列当前的状态为j时有多少种方案
//状压dp,第一行表示为二进制的低位,第二行为二进制的高位
int main(){
    int n; cin >> n;
    //初始状态赋初值
    f[1][0] = 1;
    for (int i = 1; i <= n; i ++ ){ 
        for (int j = 0; j < 4; j ++ ){ //j, k枚举的都是状态
            for (int k = 0; k < 4; k ++ ){
                //f[i][j] * g[j][k]表示从状态j能否变到状态k,如果可以就会累加结果并除于
                f[i + 1][k] = (f[i + 1][k] + f[i][j] * g[j][k]) % mod;
            }
        }
    }
    cout << f[n + 1][0] << endl;
    return 0;
}

扫雷

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
扫雷题目链接

代码

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

using namespace std;
typedef long long LL;

const int N = 50010, M = 999997; //(5e4 + 5e4) * 10,这里hash表开大了约雷和火箭的十倍,取了一个质数

int n, m;
struct Circle
{
    int x, y, r;
}cir[N];
LL h[M]; //hash数组
int id[M];
bool st[M];
//转化成一个1e9+1进制的数字
LL get_key(int x, int y)
{
    return x * 1000000001ll + y; //ll是表示它1e9+1是一个long long型的数字
}
//手写hash
int find(int x, int y)
{
    //将坐标(x, y)转化成一个1e9+1进制的数key
    LL key = get_key(x, y);
    //将key映射成999997(M)以内的数t
    int t = (key % M + M) % M; //避免key为负数
    //如果映射的t被用过,并且不是同样映射为t的不是当前的key,那就循环找到没有被用过的t
    while (h[t] != -1 && h[t] != key)
        if ( ++ t == M)
            t = 0;
    return t;
}

int sqr(int x)
{
    return x * x;
}

void dfs(int x, int y, int r)
{
    st[find(x, y)] = true; //标记,表示雷炸啦
    //深搜该雷半径以内其他雷是否会牵连被炸
    for (int i = x - r; i <= x + r; i ++ )
        for (int j = y - r; j <= y + r; j ++ )
            if (sqr(i - x) + sqr(j - y) <= sqr(r))
            {
                int t = find(i, j);
                if (id[t] && !st[t])
                    dfs(i, j, cir[id[t]].r);
            }
}

int main()
{
    scanf("%d%d", &n, &m);
    //初始化
    memset(h, -1, sizeof h); 
    for (int i = 1; i <= n; i ++ )
    {
        int x, y, r;
        scanf("%d%d%d", &x, &y, &r);
        cir[i] = {x, y, r};

        int t = find(x, y);
        if (h[t] == -1) h[t] = get_key(x, y);
        //如果t点之前没有雷,或者之前雷的半径要小于当前雷的,那就更新t点的雷
        if (!id[t] || cir[id[t]].r < r)
            id[t] = i;
    }

    while (m -- ) //枚举火箭
    {
        int x, y, r;
        scanf("%d%d%d", &x, &y, &r);
        //方块式枚举,因为半径小于等于10,所以直接暴力枚举
        for (int i = x - r; i <= x + r; i ++ )
            for (int j = y - r; j <= y + r; j ++ )
                //枚举的是方块,所以要判断枚举的点是否在半径内,pow太费时间啦
                if (sqr(i - x) + sqr(j - y) <= sqr(r))
                {
                    int t = find(i, j);
                    if (id[t] && !st[t]) //如果t点有雷,并且之前没有被炸过,那就深搜
                        dfs(i, j, cir[id[t]].r);
                }
    }

    int res = 0;
    for (int i = 1; i <= n; i ++ )
        if (st[find(cir[i].x, cir[i].y)]) //如果雷炸过就++
            res ++ ;

    printf("%d\n", res);
    return 0;
}

李白打酒加强版

在这里插入图片描述
在这里插入图片描述
李白打酒加强版题目链接

代码

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

using namespace std;
const int N = 111, mod = 1e9 + 7;

int f[N][N][N];

int main(){
    int n, m; cin >> n >> m;
    //dp
    //f[i][j][k]当前遇到i家店,j朵花,且酒剩余k单位,的方案数
    //状态计算:当前在花:f[i][j - 1][k + 1];当前在店f[i - 1][j][k / 2];(k % 2 == 0)
    //因为最后一定是遇到花,把酒喝完,所以剩余的酒一定是小于等于剩余花的数量,确保它能喝完
    f[0][0][2] = 1;  
    for (int i = 0; i <= n; i ++ ){
        for (int j = 0; j <= m; j ++ ){
            for (int k = 0; k <= m - j + 1; k ++ ){
                if(i && k % 2 == 0) f[i][j][k] = (f[i][j][k] + f[i - 1][j][k / 2]) % mod;
                if(j) f[i][j][k] = (f[i][j][k] + f[i][j - 1][k + 1]) % mod;
            }
        }
    }
    cout << f[n][m - 1][1];
    return 0;
}

砍竹子

在这里插入图片描述
在这里插入图片描述
砍竹子题目链接

代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <stack>
#include <cmath>

using namespace std;
typedef long long LL;
const int N = 200010, M = 10;

LL f[N][M];

int main()
{
    int n, m = 0; cin >> n;
    stack<LL> stk;
    int res = 0;
    for (int i = 0; i < n; i ++ )
    {
        LL x; cin >> x;
        while (x > 1) stk.push(x), x = sqrt(x / 2 + 1);
        res += stk.size();
        m = max(m, (int)stk.size()); //记录砍竹子的最高层

        for (int j = 0; stk.size(); j ++)
            f[i][j] = stk.top(), stk.pop(); //存每一层
    }

    for (int i = 0; i < m; i ++ )
        for (int j = 1; j < n; j ++ )
        //如果与前一棵竹子有相同的砍的路径,那就可以一起砍,也就可以合并在一起
        //一层一层的枚举
            if (f[j][i] && f[j][i] == f[j - 1][i])
                res -- ;

    cout << res << endl;
    return 0;
}

以上题目图片和链接都来自acwing

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值