第十四届蓝桥杯A组真题整理

前言:少废话,直接发车

A:幸运数

蓝桥云课传送门:10.幸运数 - 蓝桥云课 (lanqiao.cn)

小蓝认为如果一个数含有偶数个数位,并且前面一半的数位之和等于后面一半的数位之和,则这个数是他的幸运数字。例如 2314 是一个幸运数字,因为它有 4 个数位,并且 2+3=1+4。现在请你帮他计算从 1 至100000000 之间共有多少个不同的幸运数字。

题解:

本题是蓝桥杯第一个题,是填空题,所以做的方法比较多,考虑到没学STL库的同学,提供一个不用字符串的方法:

写一个chk函数(检查函数)查看是否符合要求,符合的话答案累加。

bool chk(int x)
{
    int temp = x, ct = 0, _sum = 0;
    while (temp > 0)
    {
        temp /= 10;
        ct++;
    }
    if (ct % 2 == 1)
        return false;
    int mid = ct / 2;
    for (int i = 1; i <= mid; i++)
    {
        _sum += x % 10;
        x /= 10;
    }
    for (int i = mid; i <= ct; i++)
    {
        _sum -= x % 10;
        x /= 10;
    }
    return _sum==0;
}

传入的x是要去判断的数字,三个变量temp,ct,_sum,temp和ct用来计算x的数字位数,如果是偶数那么就继续操作,如果是奇数位数直接返回false,因为奇数位数不可能是幸运数字。_sum首先累加x后半部分每一位上的数字,再减去前半部分每一位上的数字,如果是0,那么就是幸运数字,反之则不是。

学过STL库的同学可以直接比较前后string的ascll码,代码太简单不写了。还有各种前缀和,开二维数组的更快速的方法这里都不提及,一是我不会,二是对新人不友好,看题解写的花里胡哨的多半都是炫技的。能快速写出来并且正确的代码就是好代码。

写main函数:

int main()
{
    int ans = 0;
    for (int i = 1; i <= 100000000; i++)
    {
        if (chk(i))
        {
            ans++;
        }
    }
    cout << ans;
    return 0;
}

这样输出答案之后就能得到,在提供答案的时候定不要一直接把程序直接交上,这是填空题,而且暴力遍历下来会超时,你要提交的是下面这种

#include <iostream>
using naespace std;
int main (){
cout<<4430091;
return 0;
}

放在签到题里算有难度的,但还是签到题,基本参赛选手都能得分,所以要仔细检查,尽量不要丢分。 

B:有奖问答

蓝桥云课传送门:1.有奖问答 - 蓝桥云课 (lanqiao.cn)

小蓝正在参与一个现场问答的节目。活动中一共有 30 道题目,每题只有答对和答错两种情况,每答对一题得 10 分,答错一题分数归零。

小蓝可以在任意时刻结束答题并获得目前分数对应的奖项,之后不能再答任何题目。最高奖项需要 100 分,所以到达 100 分时小蓝会直接停止答题。

已知小蓝最终实际获得了 70 分对应的奖项,请问小蓝所有可能的答题情况有多少种?

题解:

这种询问有多少种可能的情况的,多半涉及dfs(深度优先搜索),到这一题开始,没学过算法的同学就要开始罚坐了,没关系,你现在看见就算完全不会也来得及。dfs的用途不在此提及,但我会负责在这里说明白这个题

根据题目模拟参赛情况的话,有两种强制停止答题的情况,第一是答够了30题,第二是答满了100分。符合答案的情况是任何时刻得到七十分(因为小蓝自己可以停止答题)。

我们把定义一个变量ans用来记录答案,给出代码:

void dfs(int a, int b)//a用来记录题目数量,b用来记录分数
{
    if (a >= 100 || b >= 31)//强制退出的两种情况
    {
        return;
    }
    if (a == 70)//满足条件则累加
    {
        ans++;
    }
    dfs(a + 10, b + 1);//这是答对了下一题的情况
    dfs(0, b + 1);//这是答错下一题的情况
}

请注意,敏锐的同学可能发现,在一次模拟答题的过程中,可能会有多次累加答案的情况,比如说第七题得到70分,第十五题又得到70分,这是符合题意的,因为第七题的那次记录意味着小蓝在此停止了答题,而第十五题的记录是第七题之后继续答题的情况。 

主函数很精炼,变量ans开在头文件下面了,记得开就行

int main()
{
    dfs(0, 0);
    cout << ans;
    return 0;
}

同样,这题是一道填空题,我的朋友,相信照猫画虎难不倒你。

多扯一句:洛谷上这个题的测试数据有误,建议直接飞蓝桥云课题库。 虽然题目标签是dp,但是填空题唯一真神,我的朋友,暴力搜索。

C:平方差

蓝桥云课传送门:2.平方差 - 蓝桥云课 (lanqiao.cn)

给定 L, R,问 L ≤ x ≤ R 中有多少个数 x 满足存在整数 y,z 使得 x=y^{2}-z^{2}

输入:输入一行包含两个整数 L,R,用一个空格分隔。

输出:输出一行包含一个整数,表示满足题目给定条件的的数量。

题解:

没见过相关的数学公式,那么我认为这是一道思维题。对于这种摆明了难度不是很大的思维题(因为放在前面),一个很好用的策略就是逐个枚举,找规律。

先枚举一到十之间的x:

有点猫腻,但是不太确定,再来枚举十一到二十之间的x:

好像符合条件的x都是三个一组三个一组的出现,19和20以及21也是符合条件的x,那么答案自己就跳出来了,从2开始,每往下4个数就是一个不符合条件的数,剩下都是符合条件的x。轻而易举,轻而易举啊哈哈哈!我们只需要用算上L到R的所有数,再减去不符合条件的,就是答案。

因为每个数都要检测,所以时间复杂度是O(n),出乎我意料的是O(n)也只无法AC,提交运行之后是90分,最后一条TLE了,在实际比赛中,九十分也可以了说是,那么给出代码:

#include <iostream>
using namespace std;
using ll = long long;
bool chk(ll x)//检测是否是需要剔除的数
{
  return (x - 2) % 4 == 0;
}
int main()
{
  ll l, r;
  cin >> l >> r;
  ll ans = r - l + 1;
  for (ll i = l; i <= r; i++)
  {
    if (chk(i))
      ans--;//如果需要剔除,那么就答案减1
  }
  cout << ans;
  return 0;
}

看着九十分的方案,我的内心陷入了沉思,真是难过,自以为是的结果就仅仅如此了吗!可恶,还不够,这是OI能得到90分,那如果是ICPC呢?!九十分和零分毫无差别!

所以一定有更优的逻辑,我们再来看刚才枚举的例子:

在刚开始的思路中,我们对四取模,这个四,总令人很在意,一定还有什么规律,在四里面,救赎之道,就在其中!

我们看所有的偶数,都是四的倍数,剩下的所有奇数都符合要求,那么我们就可以转换思路,去看看L到R中有多少奇数和四的倍数,并且要脱离逐个枚举验证的方式,不能直接用(R-L+1)/2这样统计奇数(比如3到5和4到6,一样的差值,但是所含奇数不同),直接求L到R之间的不好求,但是我的朋友,0到L和0到R之间的奇数个数是很好求的,(N+1)/2就是0到N之间奇数的个数,那么零到四之间四的倍数的个数,就直接用N/4就能得出结果,分别用R和L-1(因为L本身也算在里面,所以减去的是L-1的个数)代入N,然后作差就能得出答案,所以我们就有了O(1)的算法,轻而易举,轻而易举啊!来热血澎湃的敲出代码吧!

#include <iostream>
using namespace std;
using ll = long long;
ll l, r, ans = 0;
ll f(ll x)
{
  ll temp1, temp2;
  temp1 = (x + 1) / 2;//奇数个数
  temp2 = x / 4;//四的倍数的个数
  return temp1 + temp2;
}
int main()
{
  cin >> l >> r;
  ans = f(r) - f(l - 1);
  cout << ans << endl;
  return 0;
}

提交然后,过辣!!!!

D:更小的数

蓝桥云课传送门:1.更小的数 - 蓝桥云课 (lanqiao.cn)

小蓝有一个长度均为 n 且仅由数字字符0~9组成的字符串,下标从0到n -1,你可以将其视作是一个具有 , 位的十进制数字 num,小蓝可以从num 中选出一段连续的子串并将子串进行反转,最多反转一次。小蓝想要将选出的子串进行反转后再放入原位置处得到的新的数字 {num_{new}}^{} 满足条件 {num_{new}}^{}< num,请你帮他计算下一共有多少种不同的子串选择方案,只要两个子串在 num 中的位置不完全相同我们就视作是不同的方案。
注意,我们允许前导零的存在,即数字的最高位可以是 0,这是合法的。

输入:输入一行包含一个长度为 n 的字符串表示 num(仅包含数字字符 0~ 9),从左至右下标依次为0~n-1。

输出:输出一行包含一个整数表示答案。

题解:

思路:双指针从两头往中间找,找到不同的数就开始比,如果左大于右,那就符合,答案累加。

蓝桥云课给的标签是DP,但是以我的水平,不固定起点,我不会写状态转移方程,所以就先写了爆搜试了下,结果又双出乎我的意料,O(n^3)AK了,可能是给的数据比较水,不过人都给满昏了,就不再探讨,直接给出代码:

// 更小的数
#include <iostream>
#include <string>
using namespace std;
const int N = 5005;
using ll = long long;
int n;
string num;
ll ans = 0;
int main()
{
  cin >> num;
  n = num.size();//获取长度
  for (int i = 0; i < n; i++)//左端点
  {
    for (int j = i + 1; j < n; j++)//右端点
    {
      int l = i, r = j;
      while (num[r] == num[l] && l < r)//如果左右相同,往中间找,同时确保l<r
      {
        l++;
        r--;
      }//一旦左右不相等或者遍历完毕字符串,就结束while
      if (num[l] > num[r])//如果满足题目条件,左值小于右值,则答案加1
        ans++;
    }
  }
  cout << ans << endl;
  return 0;
}

E 颜色平衡树

参考算法:树上启发式合并

题解:

蓝桥云课传送门:1.颜色平衡树 - 蓝桥云课 (lanqiao.cn)

注意!!!:重量级选手,考察了数据结构,图论,没基础不建议硬啃,可以跳到F题,F题是个DFS加剪枝优化

看题解说是也可以用树上莫队,线段树合并来做,但是从复杂度分析都没有树上启发式合并更优

链式前向星存图:

int head[N<<1],cnt_edge=0;
struct E{
int to,next;//to是该起点对应的终点,next是以该起点为起点的下一条边的编号
}edge[N<<1];

void add_edge(int u,int v){//无向边存图
edge[cnt_edge]={u,head[v]};
head[v]=cnt_edge++;
edge[cnt_edge]={v,head[u]};
head[u]=cnt_edge++;
}

如果看不懂可以稍微查一下链式前向星的知识,一看就明白,在这不再赘述。

简单说一下树上启发式合并:

树上启发式合并(DSU on Tree)是一种解决树上离线问题的有力算法,主要优化的是暴力算法的“合并”过程。它的核心思想是将“小的结构”合并到“大的结构”中,并且只增加“小的结构的代价”,以此来减少时间复杂度。

具体来说,对于每个节点,如果它的信息能够通过其子树合并得来,那么就选择一个子树(通常选择重儿子)作为预先的信息。这样,在合并过程中,只需将其他子树(轻儿子)的信息暴力合并到重儿子上,从而避免了重复遍历。这种方法的关键在于继承重儿子的信息,并确保在统计过程中不再暴力统计重儿子,以保持算法的正确性。

在实际应用中,树上启发式合并的复杂度通常可以达到O(nlogn),其中n是树中节点的数量。这是因为在遍历过程中,每个节点到根节点的轻边数量最多为logn条,所以每个节点最多会被暴力统计log次。

总的来说,树上启发式合并是一种有效的数据结构优化算法,适用于解决树上的离线问题,如统计每个子树中特定元素的数量或计算每个节点的特定贡献等。

以上取自文心一言

直接上代码吧

#include <iostream>
using namespace std;
using ll = long long;
const int N = 200000 + 5;
struct E
{
  ll to, next;
} edge[N << 2];
ll cnt_edge = 0, head[N << 2];
void add_edge(ll u, ll v)//链式前向星存图
{
  edge[cnt_edge] = {v, head[u]};
  head[u] = cnt_edge++;
  edge[cnt_edge] = {u, head[v]};
  head[v] = cnt_edge++;
}
struct Node
{
  ll sz, hson, col, f;
} node[N];
void dfs_hson(ll u, ll f)//树剖找重儿子
{
  node[u].sz = 1;//初始大小为1,后面还要加上儿子们的大小
  node[u].f = f;
  ll maxsz = 0;
  for (ll i = head[u]; i != -1; i = edge[i].next)//遍历子树
  {
    ll v = edge[i].to;
    if (v == f)//因为是无向图,往父亲跑就跳过
      continue;
    dfs_hson(v, u);
    node[u].sz += node[v].sz;
    if (node[v].sz > maxsz)//更新重儿子
    {
      maxsz = node[v].sz;
      node[u].hson = v;
    }
  }
}
ll flag = 0, maxcol, cnt_c[N], cur_sum;//flag用来临时标记重儿子,maxcol是当前出现最多的颜色编号,cur_sum是当前出现最多次数的所有颜色出现的次数总和
void count(ll u, ll f, ll val)//统计子树贡献
{
  cnt_c[node[u].col] += val;//这里val可以是正1或者负1,负1是为了消除轻儿子贡献
  if (cnt_c[node[u].col] > cnt_c[maxcol])//更新出现最多次数的颜色
  {
    maxcol = node[u].col;
    cur_sum = cnt_c[node[u].col];
  }

  else if (cnt_c[node[u].col] == cnt_c[maxcol])
  {
    if (node[u].col == maxcol)//如果这次增加的是之前那个最大的颜色,那只需要更新就行了
    {
      cur_sum = cnt_c[maxcol];
    }
    else//如果这次是出现次数和最多相同的其他颜色,那么就需要累加起来
      cur_sum += cnt_c[maxcol];
  }
  for (ll i = head[u]; i != -1; i = edge[i].next)
  {
    ll v = edge[i].to;
    if (v == f || v == flag)//跳过父亲和重儿子
      continue;
    count(v, u, val);
  }
}
ll ans = 0;
void dfs(ll u, ll f, bool op)
{
  for (int i = head[u]; i != -1; i = edge[i].next)
  {
    ll v = edge[i].to;
    if (v == f || v == node[u].hson)
      continue;
    dfs(v, u, false);
  }
  if (node[u].hson)
  {
    dfs(node[u].hson, u, true);
    flag = node[u].hson;
  }
  count(u, f, 1);
  flag = 0;//用完即时清零防止出现意外
  if (cur_sum == node[u].sz)//如果出现最多的所有颜色出现次数之和等于总尺寸,那就说明是颜色平衡树
  {
    ans++;
  }
  if (!op)//轻儿子就先删除贡献
  {
    count(u, f, -1);
    maxcol = cur_sum = 0;//count里面会影响maxcol和cur_sum,清零防止扰乱
  }
}
ll n;
int main()
{
  for (ll i = 0; i < N << 2; i++)//初始化head数组
    head[i] = -1;
  cin >> n;
  for (int i = 1; i <= n; i++)//存图
  {
    ll temp1, temp2;
    cin >> temp1 >> temp2;
    add_edge(i, temp2);
    node[i].col = temp1;
    node[i].f = temp2;
  }
  dfs_hson(1, 0);//找重儿子
  dfs(1, 0, true);//遍历树
  cout << ans;
  return 0;
}

F 买瓜

蓝桥云课传送门:1.买瓜 - 蓝桥云课 (lanqiao.cn)

小蓝正在一个瓜摊上买瓜。瓜摊上共有n个瓜,每个瓜的重量为 A_{i}
小蓝刀功了得,他可以把任何瓜劈成完全等重的两份,不过每个瓜只能劈1刀。
小蓝希望买到的瓜的重量的和恰好为 m。
请问小蓝至少要劈多少个瓜才能买到重量恰好为 m 的瓜。如果无论怎样小蓝都无法得到总重恰好为 m 的瓜,请输出 -1。

输入:输入的第一行包含两个整数n,m,用一个空格分隔,分别表示瓜的个数和小蓝想买到的瓜的总重量。
第二行包含 n 个整数 A;,相邻整数之间使用一个空格分隔,分别表示每个瓜的重量。

输出:输出一行包含一个整数表示答案。

题解:

数据范围是n<=30,然后求劈的最少刀数,可以考虑用深度优先搜索,不卖关子了,这个题非常考察优化,不剪枝,只能得40以下,不排序只能得七十分以下,只有剪枝做好了,再加上排序预处理,才能AC。

每个西瓜有三种处理方法:即拿一整个,劈一半,或者不拿,所以算法复杂度是O(n^3)

首先,要想剪枝,基本就是头递归,即数据处理在递归之前。剪枝可以从两个角度考虑,如果当前积累的西瓜重量已经超过m,或者当前西瓜重量总数加上剩余所有西瓜重量都不够m,这两种情况都要提前终止。

排序的原因:假如你要往一个杯子里放石头,你是先放大的还是先放小的,言尽于此。

注意剪枝和排序之后,就是一道很简单的爆搜了,给出代码:

#include <iostream>
#include <climits>
#include <algorithm>
using namespace std;
using ll = long long;
ll n, m, a[35], ans = INT_MAX, remain = 0;
bool cmp(ll a, ll b)
{
  return a > b;
}
void dfs(ll u, ll re, ll cnt, ll _sum)
{
  if (_sum == m) // 先计算是否正好是m个
  {
    ans = min(ans, cnt);//更新答案
    return;
  }
  if (u > n || re + _sum < m || _sum > m) // 再考虑跳出
  {
    return;
  }
  dfs(u + 1, re - a[u], cnt, _sum);//当前这个西瓜不拿
  dfs(u + 1, re - a[u], cnt, _sum + a[u]);//当前这个西瓜拿一整个
  dfs(u + 1, re - a[u], cnt + 1, _sum + a[u] / 2);//给当前这个西瓜来一刀,拿一半
}
int main()
{
  cin >> n >> m;
  m *= 2;//因为之后所有西瓜也翻倍了,算是预处理,先往下看
  for (int i = 1; i <= n; i++)
  {
    cin >> a[i];
    a[i] *= 2;//因为之后可能要涉及除以二的操作,所以这里预先乘2,以防出现小数,不用double类型的原因是,double太慢了。
    remain += a[i];
  }
  sort(a + 1, a + n + 1, cmp);//从大到小排序
  dfs(0, remain, 0, 0);
  if (ans == INT_MAX)
    ans = -1;
  cout << ans;
  return 0;
}

G题是位运算模拟,F题是防AK的高级数论题,本人能力实在不够,QWQ

  • 59
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是第十四届蓝桥杯Python组真题的部分内容: 一、选择题(每题5分,共40分) 1. 下列哪个不是Python的内置数据类型? A. int B. float C. char D. str 答案:C 2. 下列哪个不是Python的保留字? A. and B. or C. not D. xor 答案:D 3. 下列哪个不是Python的标准模块? A. os B. sys C. math D. timeit 答案:D 4. 下列哪个Python库可以用于科学计算? A. NumPy B. SciPy C. Matplotlib D. All of the above 答案:D 5. 下列哪个Python库可以用于机器学习? A. TensorFlow B. Keras C. PyTorch D. All of the above 答案:D 6. 下列哪个Python库可以用于爬虫? A. Requests B. BeautifulSoup C. Scrapy D. All of the above 答案:D 7. 下列哪个Python库可以用于图像处理? . OpenCV B. Pillow C. Scikit-image D. All of the above 答案:D 8. 下列哪个Python库可以用于游戏开发? A. Pygame B. Panda3D C. PyOpenGL . All of the above 答案:D 二、编程题(每题20分,共60分) 1. 编写一个Python程序,输入一个字符串,将其中的大写字母转换为小写字母,将其中的小写字母转换为大写字母,然后输出转换后的字符串。 2. 编写一个Python程序,输入一个整数n,输出n的阶乘。 3. 编写一个Python程序,输入一个字符串,判断该字符串是否为回文字符串。如果是回文字符串,则输出True,否则输出False。 以上是部分内容,完整的第十四届蓝桥杯Python组真题可以在蓝桥杯官网上找到。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值