蓝桥杯2022初赛 题解

2031: [蓝桥杯2022初赛] 九进制转十进制

九进制正整数(2022) 转换成十进制等于多少?

这是一道结果填空的题,你只需要算出结果后提交即可。

本题的结果为一个整数,在提交答案时只输出这个整数,输出多余的内容将无法得分。

思路:使用电脑计算器计算(2*9^3)+(0*9^2)+(2*9^1)+(2*9^0)

2032: [蓝桥杯2022初赛] 顺子日期

小明特别喜欢顺子。顺子指的就是连续的三个数字:123、456 等。

顺子日期指的就是在日期的 yyyymmdd 表示法中,存在任意连续的三位数是一个顺子的日期。

例如20220123 就是一个顺子日期,因为它出现了一个顺子:123;

本题顺子的定义:i j k 是一个顺子,满足 i+1=j、j+1=k、i≥0

而20221023 则不是一个顺子日期,它一个顺子也没有。

小明想知道在整个2022年份中,一共有多少个顺子日期。

这是一道结果填空的题,你只需要算出结果后提交即可。

本题的结果为一个整数,在提交答案时只输出这个整数,输出多余的内容将无法得分。

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

int md[12] = { 31,29,31,30,31,30,31,31,30,31,30,31 };
int main()
{
    int i = 0;
    int c = 0;
    int d[8] = {2,0,2,2,0,1,0,0};
    int m=1;
    for (i = 0; i < 366; ++i)
    {
        ++d[7];
        if (d[7] == 10)
        {
            d[7] = 0; ++d[6];
        }

        if (d[6] * 10 + d[7] > md[m-1])
        {
            ++m;
            d[4] = m / 10;
            d[5] = m % 10;
            d[6] = 0; d[7] = 1;
        }
        for (int i2 = 4;i2<=5;++i2)
        {
            if (d[i2] +2 == d[i2 + 1] + 1 && d[i2 + 1] + 1 == d[i2 + 2])
            {
                ++c;
                break;
            }
        }
    }
    cout << c;
}

思路:将日期的每个数字分别存在数组里,对每个日期都判断是否存在顺子数,但是经过思考发现可以不考虑年份数字(前四个数字),因为它不可能和后面的数字组成顺子数,所以循环中i2的初值设定为了4而不是0,实际检测日期是否存在顺子数只需要判断两次。

2033: [蓝桥杯2022初赛] 刷题统计

小明决定从下周一开始努力刷题准备蓝桥杯竞赛。

他计划周一至周五每天做 a 道题目,周六和周日每天做 b 道题目。

请你帮小明计算,按照计划他将在第几天实现做题数大于等于 n 题?

#include<iostream>
using namespace std;

int main()
{
    long long wo,we,aim,w,l,i;
    cin>>wo>>we>>aim;
    w = aim/(5*wo+2*we);
    l = aim%(5*wo+2*we);
    long long week[7] = {wo,wo,wo,wo,wo,we,we};
    for(i=0;l>0;++i)
    {
        l-=week[i];
    }
    cout<<w*7+i;
}

思路:先用总题量除以每周题量将天数精确到一星期以内,再使用循环将剩下的题量减掉,直到剩余题量小于1为止。

2034: [蓝桥杯2022初赛] 修剪灌木

爱丽丝要完成一项修剪灌木的工作。

有 N 棵灌木整齐的从左到右排成一排。

爱丽丝在每天傍晚会修剪一棵灌木,让灌木的高度变为 0 厘米。

爱丽丝修剪灌木的顺序是从最左侧的灌木开始,每天向右修剪一棵灌木。

当修剪了最右侧的灌木后,她会调转方向,下一天开始向左修剪灌木。

直到修剪了最左的灌木后再次调转方向。然后如此循环往复。

灌木每天从早上到傍晚会长高 1 厘米,而其余时间不会长高。

在第一天的早晨,所有灌木的高度都是 0 厘米。爱丽丝想知道每棵灌木最高长到多高。

输入格式

一个正整数N ,含义如题面所述。

30%的测试数据:1<N≤10;

100%的测试数据:1<N≤10000。

输出格式

输出 N 行,每行一个整数,第 i 行表示从左到右第 i 棵树最高能长到多高。

#include<iostream>
using namespace std;
int main()
{
    int n,i;
    cin>>n;
    for(i=1;i<=n/2;++i)
    cout<<2*(n-i)<<endl;
    for(i=n/2+1;i<=n;++i)
    cout<<2*(i-1)<<endl;

}

思路:手算4棵树的情况,寻找规律,发现离中心越远树能长的就越高,之后不断修改代码直到符合样例。

2035: [蓝桥杯2022初赛] X进制减法

题目描述

进制规定了数字在数位上逢几进一。

X 进制是一种很神奇的进制,因为其每一数位的进制并不固定!

例如说某种X 进制数,最低数位为二进制,第二数位为十进制,第三数位为八进制:

则 X 进制数321 转换为十进制数为65。65=3*(2*10)+2*(2)+1*(1)。

现在有两个 X 进制表示的整数 A 和 B,但是其具体每一数位的进制还不确定。

只知道 A 和 B 是同一进制规则,且每一数位最高为 N 进制,最低为二进制。

请你算出 A − B 的结果最小可能是多少。

请注意,你需要保证 A 和 B 在 X 进制下都是合法的,即每一数位上的数字要小于其进制。

输入格式

第一行一个正整数 N,含义如题面所述。

第二行一个正整数 Ma,表示 X 进制数 A 的位数。

第三行 Ma 个用空格分开的整数,表示 X 进制数 A 按从高位到低位顺序各个数位上的数字在十进制下的表示。

第四行一个正整数 Mb,表示 X 进制数 B 的位数。

第五行 Mb 个用空格分开的整数,表示 X 进制数 B 按从高位到低位顺序各个数位上的数字在十进制下的表示。

请注意,输入中的所有数字都是十进制的。

30%的测试数据:2≤N≤10,1≤Ma,Mb≤8。

100%的测试数据:2≤N≤1000,1≤Ma,Mb≤100000,B≤A。

输出格式

输出一行一个整数,表示X 进制数A − B 的结果的最小可能值转换为十进制后再模1000000007 的结果。

#include <iostream>
#include <set>
#include<map>
#include <vector>
#include<math.h>
using namespace std;
const int N = 100004;
int a[N], b[N];

int main()
{
    int n, ma, mb, i;
    long long output = 0;

    cin >> n;
    cin >> ma;
    for (i = 0; i < ma; ++i)
    {
        cin >> a[i];
    }
    cin >> mb;
    for (i = ma - mb; i < ma; ++i)
    {
        cin >> b[i];
    }
    for (i = 0; i < ma - 1; ++i)
    {
        output = (output+ (a[i] - b[i])) * max(2, max(a[i + 1], b[i + 1]) + 1)% 1000000007;
    }
    cout << (output + a[i] - b[i]+ 1000000007) % 1000000007;
}

题目解析:

先举个例子:假若两个x进制数相减(A-B),设A为四位数abcd、B为三位数efg,每一位进制为h1 h2 h3 h4

则结果的计算方法为:

先将最高位的a转到第3位,则第3位的值为a*h2+b-e

再将第3位的值转到下一位,则第2位的值为(a*h2+b-e)*h3 +c-f

以此类推,A-B的值为((((a*h2)+b-e)*h3+c-f)*h4)+d-g

因为A>B(题目条件),所以可以判断出,对于A-B,每次将一位的值转换到下一位的时候,下一位的值总为正

因此,想要让最后的值最小,只需让每一位的进制最小即可,即h2 h3 h4最小(h1在本题中是没用的值,同样没用的还有每位的最高位数N,因为我们需要求的是最小值)

计算每一位的最小值的方法:

首先,每一位的进制必须大于等于2(题目条件)

其次,每一位的进制必须大于等于这个位的值+1,否则这一位就可以进位了,因为数A和数B每一位的进制相同

所以实际上求的是max(2,max(A该位的值,B该位的值)+1)

求出来后,按照上述方法计算出结果即可,需要注意的是,A和B位数不一定相等,用数组接受B时需要从正确的位数开始输入

2036: [蓝桥杯2022初赛] 统计子矩阵

题目描述

给定一个 N × M 的矩阵A,请你统计有多少个子矩阵(最小 1 × 1,最大 N × M) 满足:

子矩阵中所有数的和不超过给定的整数K?

输入格式

第一行包含三个整数N, M 和K.

之后 N 行每行包含 M 个整数,代表矩阵A.

30%的测试数据:1≤N,M≤20;

70%的测试数据:1≤N,M≤100;

100%的测试数据:1≤N,M≤500;0≤Aij≤1000;1≤K≤250000000。

输出格式

一个整数代表答案。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
//#include <set>
//#include<map>
//#include <vector>
//#include<math.h>
using namespace std;
const int N = 502;
//首先建一个502*502的数组,因为后面的操作可能会越界,所以我们从(1,1)开始输入而不是(0,0)以空出边界
long long summ[N][N];



int main()
{
    int n, m, i, i2;
    long long k, output = 0;
    cin >> n >> m >> k;
    for (i = 1; i <= n; ++i)
    {
        for (i2 = 1; i2 <= m; ++i2)
        {
            scanf("%lld", &summ[i][i2]);
            summ[i][i2] += summ[i - 1][i2] + summ[i][i2 - 1] - summ[i - 1][i2 - 1];
        }
        //注意:数组记录的不是当前坐标的值,而是当前坐标到(1,1)坐标形成的矩形区域的总和值
        //这样可以快速计算出每个矩形的总值而不需要一个一个算
    }

    //枚举每一个矩形会超时,通过以下方法可以排除掉已经不需要再判断的矩形:
    /*
    1.枚举矩形所有的左界右界和上界(分别用用a,d,w表示,下界用s表示)
    2.以上界w为起点开始遍历下界,一旦发现当前矩形的值大于k则立刻停止,因为再向下遍历值也肯定大于k
    3.计算出已经符合条件的矩形数量(s-w)
    4.++w,然后以上次的s为起点继续遍历,因为w坐标变大了,w~s-1之间的值肯定小于k,故排除
    注:因为矩形数量是用坐标差计算的,所以排除(直接坐标跳过)的矩形也会被计算到
    */
    int w, s, a, d;
    for (a = 1; a <= m; ++a)
    {
        for (d = a; d <= m; ++d)
        {
            for (w = 1, maxs = 0,s=1; w <= n; ++w)
            {
                for (/*这里没有对s初始化,以继承上一次的s值*/; s <= n && summ[s][d] - summ[s][a - 1] - summ[w - 1][d] + summ[w - 1][a - 1] <= k; ++s)
                {
                }
                output += s - w;
            }

        }
    }
    cout << output;
}

思路:见注释

2037: [蓝桥杯2022初赛] 积木画

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
//#include <set>
//#include<map>
//#include <vector>
//#include<math.h>
using namespace std;
const int N = 10000005;
long long num[N] = {1,1,2};

int main()
{
    int n,i;
    cin >> n;
    for (i = 3; i <= n; ++i)
    {
        num[i] = (2*num[i - 1] + num[i-3]) % 1000000007;
    }
    cout << num[n];
}

题目解析:

本题的思路是将当前的情况拆成之前的情况与一种新情况的组合

在本题中,这两种情况的要求是边必须是平整的,不然很难分情况讨论。

从i=1开始讨论,当宽度为1时,只有一种摆法

当i=2时,有2种摆法

i=3时,5种摆法

而且可以想出,i=0时,只有一种摆法(什么都不摆)

接下来我们可以用这几组初始数据去模拟i>=3的情况

但是我们发现,并不能将接下来的情况全部看作以上摆法的拼凑

如上图,当两边都是平整割面时,就可以拆为i=1或2的情况,否则不可拆

实际上只有两种情况,无法分割成为上面的摆法,如下:

开头说过,我们程序的思路是:

将拼图拆成i-k和k

先搞到前面的i-k的情况,再讨论接下来k的情况(同时也要特殊考虑这种无法分割的情况)

所以,程序的详细思路是这样的:

  1. 先直接给出i=0,i=1,i=2的情况num[N] = {1,1,2};

  1. 从i=3开始算

首先将i=3分割为i-k=1k=2,则左边i-k有1种摆法,右边k有2种摆法,总共1*2=2种摆法

然后分割为i-k=2k=1,按理说会得到2*1=2种摆法,但是我们对比下上面两种分割方法:

所以分割为i-k=2,k=1时,实际上只多了一种摆法,另一种摆法是i-k=1,k=2的情况之一。

故总共只多了2-1种摆法

接下来分割为i-k=3,k=0。因为出现了i-k>=3,我们需要考虑之前说过的,无法拆分的摆法

也就是下面的摆法:

这两种摆法就是上面提到的不可分割的摆法,它们互为镜像。

除了这两个摆法外,其它任何摆法都可以拆成i=1或i=2的情况,也就会重复,所以不讨论。

也就是: i=3时新增两种摆法,乘以i=0时的1种摆法,总共新增2种摆法

也就是有2*1种摆法

总共加起来,i=3时有2+1+2=5种摆法。

故num[3]=5 (注:num内的数表示这个长度内的所有摆法数)

从i=3的案例中已经可以模糊地意识到,如果将i拆成i-k和k,那么当i-k>=3时,新增加的摆法都是不可分割的摆法,其它摆法都可以拆成i=1或i=2的摆法,会发生重复,故可忽略。

  1. 计算i=4

当i-k=1,k=3

左边1种摆法(num[1]),右边num[3]=5

当i-k=2,k=2

左边1种摆法(num[2]-重复摆法),右边num[2]=2种摆法

当i-k=3,k=1

左边2种摆法(num[3]-重复摆法,也就是两种不可拆的摆法),右边num[1]=1种摆法

i-k=4,k=0

左边2种互为镜像的不可拆摆法,右边num[0]=1种摆法

总计1*5+1*2+2*1+2*1=11种

  1. 计算i=n

已经能找到规律了。

i-k=1,1种

i-k=2,1种,(有一种重复了故删去)

对于随后的i-k>=3,每一个i-k都只看两种互为镜像的不可拆摆法,因为其它摆法都可以拆为i=1或i=2,故重复

最后的总摆法就是每一个f(i-k)*num[k]的总和

f(i-k) =1(i-k<=2)

=2(i-k>2)

最后的算式就是

num[i] = num[i-1]*1+num[i-2]*1+num[i-3]*2+num[i-4]*2+......num[1]*2+num[0]*2

则可得出num[i]-num[i-1] = num[i-1]+num[i-3]

即num[i] = 2*num[i-1]+num[i-3]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值