蓝桥杯2022初赛题解C++(未完成)

最近在学校事有点多,题解写到G,还未完成。

新人第一次写题解,题解写的不好还请谅解。

A.九进制转十进制

题目描述
九进制正整数(2022) 转换成十进制等于多少?
这是一道结果填空的题,你只需要算出结果后提交即可。
本题的结果为一个整数,在提交答案时只输出这个整数,输出多余的内容将无法得分。

本题是一个基础的进制转换问题,直接口算即可。

列式为2+2*9+2*9*9*9,不想算直接打在代码上即可。

#include<stdio.h>
int main()
{
    printf("%d",2+2*9+2*9*9*9);
    return 0;
}

B.顺子日期

题目描述
小明特别喜欢顺子。顺子指的就是连续的三个数字:123、456 等。
顺子日期指的就是在日期的 yyyymmdd 表示法中,存在任意连续的三位数是一个顺子的日期。
例如20220123 就是一个顺子日期,因为它出现了一个顺子:123;
本题顺子的定义:i j k 是一个顺子,满足 i+1=j、j+1=k、i≥0
而20221023 则不是一个顺子日期,它一个顺子也没有。
小明想知道在整个2022年份中,一共有多少个顺子日期。
这是一道结果填空的题,你只需要算出结果后提交即可。
本题的结果为一个整数,在提交答案时只输出这个整数,输出多余的内容将无法得分。

本题可以自己手算,直接输出答案14即可。

#include<stdio.h>
int main()
{
    printf("14");
    return 0;
}

也可以把2022年的日期遍历一遍,每次检查后四位就行,因为数据量少所以不用优化什么也能过。

#include<stdio.h>
int main()
{
    int a[12]={31,28,31,30,31,30,31,31,30,31,30,31};//每个月的日期
    int i,j,ans=0;
    char b[4];
    for(i=1;i<=12;i++)
    {
        for(j=1;j<=a[i-1];j++)
        {
            b[0]=i/10+48;
            b[1]=i%10+48;
            b[2]=j/10+48;
            b[3]=j%10+48;//将每位转化成字符输入字符串中
            if((b[1]-b[0]==b[2]-b[1]||b[2]-b[1]==b[3]-b[2])&&b[2]-b[1]==1)
            ans++;//符合条件的ans计数+1。
        }
    }
    printf("%d",ans);
    return 0;
}

C.刷题统计

题目描述
小明决定从下周一开始努力刷题准备蓝桥杯竞赛。
他计划周一至周五每天做 a 道题目,周六和周日每天做 b 道题目。
请你帮小明计算,按照计划他将在第几天实现做题数大于等于 n 题?
输入格式
输入一行包含三个整数a, b 和n.
50% 的评测用例:1 ≤ a, b, n ≤ 10^6;
100% 的评测用例:1 ≤ a, b, n ≤ 10^18。
输出格式
输出一个整数代表天数。
输入样例
10 20 99
输出样例
8

本题100%的用例最大为10^18,因此需要使用long long int 来保存。

首先我们算出小明每周刷几道题(all),再算出总共要写多少个完整周(week),然后算出剩余的题数(remain),最后算出剩余的天数再相加即可。

#include<stdio.h>
int main()
{
    long long int a,b,all,remain,n,week,sum;//all一周多少题,week多少完整星期,remain剩余的题目,sum天数
    scanf("%lld%lld%lld",&a,&b,&n);
    all=5*a+2*b;//每周刷的题数
    week=n/all;//总共要写多少个完整周
    remain=n-all*week;//完整周后剩余的题目数
    sum=week*7;//总天数
    if(remain<=a*5)//若小于5天,则多出来的天数全部乘以a,则为题数。
    sum+=remain/a+(remain%a!=0);//若不足一天则按一天算。
    else
    {
        remain-=a*5;//减去周一到周五的题目
        sum+=6+(remain>b);//若周六后reng仍有剩余则+1
    }
    printf("%lld",sum);
    return 0;
}

D.修剪灌木

题目描述
爱丽丝要完成一项修剪灌木的工作。
有 N 棵灌木整齐的从左到右排成一排。
爱丽丝在每天傍晚会修剪一棵灌木,让灌木的高度变为 0 厘米。
爱丽丝修剪灌木的顺序是从最左侧的灌木开始,每天向右修剪一棵灌木。
当修剪了最右侧的灌木后,她会调转方向,下一天开始向左修剪灌木。
直到修剪了最左的灌木后再次调转方向。然后如此循环往复。
灌木每天从早上到傍晚会长高 1 厘米,而其余时间不会长高。
在第一天的早晨,所有灌木的高度都是 0 厘米。爱丽丝想知道每棵灌木最高长到多高。
输入格式
一个正整数N ,含义如题面所述。
30%的测试数据:1<N≤10;
100%的测试数据:1<N≤10000。
输出格式
输出 N 行,每行一个整数,第 i 行表示从左到右第 i 棵树最高能长到多高。
输入样例
3
输出样例
4
2
4

本题直接写几项找规律就行。

N=1时

0\n

N=4时

6\n4\n4\n6\n

N=5时

8\n6\n4\n6\n8\n

以下是最常规直观的思路。

#include<stdio.h>
int main()
{
    int n,i,count,max;
    scanf("%d",&n);
    count=n/2+(n%2==1);
    max=n*2;
    if(n%2==1)
    {
        for(i=0;i<count;i++)
        printf("%d\n",max-=2);
        for(i=1;i<count;i++)
        printf("%d\n",max+=2);
    }
    else
    {
        for(i=0;i<count;i++)
        printf("%d\n",max-=2);
        printf("%d\n",max);
        for(i=1;i<count;i++)
        printf("%d\n",max+=2);
    }
    return 0;
}

E.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 的结果。
输入样例
11
3
10 4 0
3
1 2 0
输出样例
94
数据范围与提示
当进制为:最低位 2 进制,第二数位 5 进制,第三数位 11 进制时,减法得到的差最小。
此时A 在十进制下是108,B 在十进制下是 14,差值是 94。

本题使用贪心算法。如果想要两个数的差值更小,则每一位的进制尽可能要小。因为A、B两个数相同位数对应的进制是相同的,每位的进制越小,转化为10进制后每位相应的差值就越小,A、B最终结果差值也就会越少。

因此我们可以将每一位分开来看。首先我们要初始化三个数组,两个用来记录A、B的值,第三个用来计进制大小,接着将所有数组中的所有元素初始化为0,防止位数不符时空位返回垃圾值影响大小判断结果,再记录最长的位数的值,然后把每一位都相互比较,挑选这两个数每一位较大的那一个数+1即为每位的进制数(进制数一定要大于已存在的最大数),最后用数学方法求A-B的值即可(我这里是每位分开求)。

在这里我用倒叙记录的方式,先记录低位,再记录高位,因为题目提到A、B位数可能并不相同,这样做可以防止位数不同时两个数组的位数对应关系岔开。

例如A:1234。B:123。

正序输入 倒叙输入

1 2 3 4 4 3 2 1

1 2 3 3 2 1

注意题目要求最低进制为2,可以使用max(jinzhi[i],2) 来确保当某位为0时算法会将此位的进制设为2而不是1。

#include<iostream>
using namespace std;
#define mod 1000000007
int main()
{
    int i,n,ma,mb;
    long long tmp=1,ans=0;
    scanf("%d%d",&n,&ma);//a的位数
    int a[100010]={0};
    for(i=ma-1;i>=0;i--)//倒叙输入防止位数不同岔开
    scanf("%d",&a[i]);//a的每位
    scanf("%d",&mb);//b的位数
    int b[100010]={0};
    for(i=mb-1;i>=0;i--)
    scanf("%d",&b[i]);//b的每位
    int maxws=max(ma,mb);//获取最大位数
    int jinzhi[maxws];//每位的进制
    for(i=0;i<maxws;i++)
    {
        jinzhi[i]=max(a[i],b[i])+1;
        ans+=((a[i]-b[i])*tmp%mod+mod)%mod;//+mod后再%mod,可以保证结果为正,适用于a[i]<b[i]的情况
        ans%=mod;
        tmp*=max(jinzhi[i],2);//最低进制为2,若某位数值为0,则取2而不是1。
        tmp%=mod;
    }
    printf("%lld\n",ans);
    return 0;
}

F.统计子矩阵

题目描述
给定一个 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。
输出格式
一个整数代表答案。
输入样例
3 4 10
1 2 3 4
5 6 7 8
9 10 11 12
输出样例
19
数据范围与提示
满足条件的子矩阵一共有19,包含:
大小为1 × 1 的有10 个。
大小为1 × 2 的有3 个。
大小为1 × 3 的有2 个。
大小为1 × 4 的有1 个。
大小为2 × 1 的有3 个。

本体我最先的想法是直接常规遍历写,但是由于算法时间复杂度高(O^4),并不能通过所有的测试点,貌似只能过80%。就像这样

   for(int i=1;i<=n;++i)
   {
       for(int j=1;j<=m;++j)
       {
           for(int k=i;k<=n;++k)
           {
                for(int h=j;h<=m;++h)
                {
                    if(s[k][h]-s[k][j-1]-s[i-1][h]+s[i-1][j-1]<=top)
                        sum+=1;
                    else break;//最简单的想法,奈何时间复杂度太高,不能过全部的测试点
                }
            }
        }
    }

所以得用双指针写,用i,j和right,left来分别限定行、列的范围,这样可以把复杂度降到(O^3),然后我们就能过了。

#include<stdio.h>
int main()
{
    int a[505][505]={0},sum[505][505]={0};//最大500,防止溢出
    int n,m,k,i,j,left,right;
    long long ans=0;//防止溢出
    scanf("%d%d%d",&n,&m,&k);
    for(i=1;i<=n;i++)
    for(j=1;j<=m;j++)
    {
        scanf("%d",&a[i][j]);
        sum[i][j]=-sum[i-1][j-1]+sum[i-1][j]+sum[i][j-1]+a[i][j];//求(1,1)到(i,j)的和
    }
    for(i=1;i<=n;i++)
    for(j=i;j<=n;j++)
    for(int left=1,right=1;right<=m;right++)
    {
        while(left<=right&&sum[j][right]-sum[i-1][right]-sum[j][left-1]+sum[i-1][left-1]>k)//判断区间和是否大于k
        left++;
        ans+=right-left+1;//在左右区间内满足条件的列数
    }
    printf("%lld",ans);
    return 0;
}

G.积木画

题目描述
小明最近迷上了积木画,有这么两种类型的积木,分别为 I 型(大小为 2 个单位面积)和 L 型(大小为 3 个单位面积):

题目配图

同时,小明有一块面积大小为 2 × N 的画布,画布由 2 × N 个 1 × 1 区域构成。
小明需要用以上两种积木将画布拼满,他想知道总共有多少种不同的方式?
积木可以任意旋转,且画布的方向固定。
输入格式
输入一个整数N,表示画布大小。
对于所有测试用例,1 ≤ N ≤ 10000000。
输出格式
输出一个整数表示答案。由于答案可能很大,所以输出其对 1000000007 取模后的值
输入样例
3
输出样例
5

题解待补充,因为图没画好。。。

#include<stdio.h>
int f[10000010]={0,1,2,5};//不定义成全局函数的话会溢出,我也不知道怎么回事
int main()
{
    int i;
    int m=1e9+7;
    int n;
    scanf("%d",&n);
    for(i=4;i<=n;++i)
    f[i] = (2*f[i-1]%m+f[i-3]%m)%m;//需分别%m否则可能会爆
    printf("%d",f[n]);
    return 0;
}

接下来的内容等有时间再补。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值