2022第十三届蓝桥杯C++ B组

这篇博客涵盖了多种算法问题的解决,包括九进制到十进制的转换、判断连续日期的方案数、计算一年中顺子日期的数量、解决刷题统计问题、理解进制减法、优化二维矩阵统计子矩阵的时间复杂度、实现积木画的线性动态规划算法,以及探讨李白打酒加强版的动态规划解法。文章通过实例代码详细解释了每种问题的思路和解决方案。
摘要由CSDN通过智能技术生成

1 九进制转十进制

手算2*9^3+2*9^1+2*9^0

答案:1478

2   顺子日期

 个人提交的是认为012也算,交了答案14

附上代码

#include<bits/stdc++.h>
using namespace std;
int m[15]={0,31,28,31,30,31,30,31,31,30,31,30,31};//月份的基本写法
int main()
{
    //分析过2022,不可能出现202234这种,所有可以直接枚举这一年的月份即可
    int ans=0;
    for(int i=1;i<=12;i++)
      for(int j=1;j<=m[i];j++)
    {
        int a1=i/10,a2=i%10,a3=j/10,a4=j%10;
        if(a1+1==a2&&a2+1==a3||a2+1==a3&&a3+1==a4) ans++;
    }
    cout<<ans<<endl;
    return 0;
}

3  刷题统计

这题很简单直接算有多少周和剩下有多少天加起来即可

代码附上

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;//数据过大得开ll
int main()
{
  ll a,b,n;
  cin>>a>>b>>n;
 ll w=n/(5*a+2*b),m=n%(5*a+2*b);//w是多少个星期,m是剩下的多少天
  if(m>5*a+b) cout<<7*w+7;//假如剩下的天数大于6天的话,则需要加上7天
  else if(m>5*a) cout<<7*w+6;//假如剩下的天数大于5天的话,则需要加上6天
  else{
    if(m%a) cout<<7*w+m/a+1;//假如m/a还有剩,也就是m%a!=0,则得加多m/a+1天
    else cout<<7*w+m/a;//否则没有剩,直接加上m/a天
  }
    return 0;
}

修剪灌木

 这题一分析就可以分析出来,要么左边最大要么右边最大

附上代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
   int n;
   cin>>n;
   for(int i=1;i<=n;i++)
       cout<<2*max(i-1,n-i)<<endl;//输出左右两边最大
    return 0;
}

X 进制减法

 

考试的时候没想明白进制怎么转换的,最后才知道是当前数乘以前几位的进制

如题目的321转为65:3*10*2+2*2+1=65;

这题根据示例盲猜进制为两个位数的最大数+1,但实际上确实这样,至于证明过程就不证了

附上我的代码

#include <iostream>
using namespace std;
typedef long long ll;
const int N=1e5+10,mod=1000000007;
int a[N],b[N];
ll c[N]={1,1};
int main()
{
  ll n,ans=0;
  cin>>n;
  ll ma,mb;
  cin>>ma;
  for(ll i=ma;i>=1;i--) cin>>a[i];
  cin>>mb;
  for(ll i=mb;i>=1;i--) cin>>b[i];
  for(ll i=1;i<=ma;i++) c[i]=(c[i-1]*(max(2,max(a[i],b[i])+1)))%mod;//处理没一位要乘以的数,也就是前i-位的进制积
  for(ll i=ma;i>=1;i--) ans+=(ll)((a[i]-b[i])*c[i-1])%mod;//每一位乘以对应的进制
  cout<<(ans%mod+mod)%mod;//由于答案可能mod出负数,这样就保证mod出是正数
 return 0;
}

6  统计子矩阵

考试时交了二维矩阵和的做法,时间复杂度O(n^4),只能过70%的数据

后来才知道把二维优化成一维前缀和,再加上双指针,时间复杂度O(n^3),直接AC

附上AC代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=510;
ll s[N][N];//定义一个求二维数组的一维前缀和,就是第j列的前缀和
int main()
{
   ll n,m,k,ans=0;
   cin>>n>>m>>k;
   for(int i=1;i<=n;i++)
     for(int j=1;j<=m;j++)
       cin>>s[i][j],s[i][j]+=s[i-1][j];
       //把上下边界中的数看成一维数组
     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++;
              }
              ans+=r-l+1;//相当于一维求子矩阵的数
             }
    cout<<ans;
    return 0;
}

 

积木画

 

 来看看线性DP

 

附上代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e7+10,mod=1e9+7;
long long f[N][3];//f[i][j]表示第i-1列填满,第i列的状态是j的方案数
/*
f[i][0]表示i-1列填满,第i列的上面填了
f[i][1]表示i-1列填满,第i列的下面填了
f[i][2]表示i-1列填满,第i列全填
*/
int main()
{
    int n;
    cin>>n;
    f[0][2]=1;//初始化为1
    for(int i=1;i<=n;i++)
    {
        //f[i-1][1]+上面放一条横的+f[i-2][2]+放一个倒L的方块
        f[i][0]=(f[i-1][1]+f[i-2][2])%mod;
        //f[i-1][0]+下面放一条横的+f[i-2][2]+放一个L的方块
        f[i][1]=(f[i-1][0]+f[i-2][2])%mod;
        // f[i-1][2]+放一条竖的长条 + f[i-2][2]+放两个横着的长条 + f[i-1][0]+J一样的方块 + f[i-1][1]+7一样的方块
        f[i][2]=(f[i-1][2]+f[i-2][2]+f[i-1][0]+f[i-1][1])%mod;
    }
    cout<<f[n][2]%mod;//输出第n横全放满的方案数
}

8  扫雷

暂时还不会

QAQ,先跳过

: 李白打酒加强版

 

 很典型的DP,但是我就是没想到,差一步就弄出来了QAQ

 

下面来看代码

#include<bits/stdc++.h>
using namespace std;
const int N=110,mod=1e9+7;
int f[N][N][N];//表示遇到i家店,j朵花,壶里酒有k斗的方案数
int main()
{
    int n,m;
    cin>>n>>m;
    f[0][0][2]=1;//初始化刚开始遇到0家店,0朵花,壶里酒有2斗的方案数
     for(int i=0;i<=n;i++)//枚举店
         for(int j=0;j<=m;j++)//枚举花
          for(int k=0;k<=m;k++)//枚举酒
           {
               int &v=f[i][j][k];//让v直接等价于f[i][j][k],能直接改变值
               if(i&&k%2==0) v=(v+f[i-1][j][k/2])%mod;//因为要从i-1与k/2转移,则要保证i>=1&&k%2==0
               if(j) v=(v+f[i][j-1][k+1])%mod;//因为要从j-1转移,则要保证j>=1
           }
    cout<<f[n][m-1][1]%mod;//因为题目说最后一次遇到花,则输出前一步
}

10 砍竹子

 

 

 考试时以为全部相同的高度就全部变,谁知道是相邻的高度相同才能一起变,直接哭死

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
vector<unordered_set<ll>> ha;
ll s(ll x)//用来更新结果
{
    return sqrt(x/2+1);
}
int main()
{
   ll n,ans=0;
   cin>>n;
   ha.resize(2);//分配空间,用滚动数组优化
  for(int i=1;i<=n;i++)//将n个数分解成最多6个数
  {
      ll x;
      cin>>x;
      while(x>1)//将x进行分解
      {
         if(!ha[i&1].count(x)) ans++;//假如不连续,也就是上一个数的set没有出现过这个数,则答案加1
         ha[i-1&1].insert(x);//把这个数放进另一列中
         x=s(x);//分解这个数
      }
      ha[i&1].clear();//把比较完的数清空,没用了
  }
  cout<<ans;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值