41 完全二叉树的权值 解题日期:250219 解题用时:40min 题目来源:蓝桥杯真题 题目难度:中等 题目标签:2019,二叉树,省赛
题意整理 完全二叉树,每个节点都有一个权值,现在要把相同深度的节点的权值加在一起,想指导哪个深度的节点权值之和最大?
解题思路 根据完全二叉树的性质进行公示推导。注意数组越界的问题,会导致运行错误。
完全二叉树的性质
AC代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 #include <iostream> #include <climits> using namespace std;int fd (int i) { if (i == 0 ) return 1 ; int result = 1 ; while (i > 0 ) { result *= 2 ; i--; } return result; } int gh (int n) { int height = 0 ; while (fd (height) <= n) { height++; } return height; } int main () { int n; cin >> n; int a[100010 ] = {0 }; for (int i = 1 ; i <= n; i++) { cin >> a[i]; } int h = gh (n); int res = 1 ; int maxSum = INT_MIN; for (int i = 1 ; i <= h; i++) { int sum = 0 ; int start = fd (i - 1 ); int end = fd (i); if (end > n) end = n + 1 ; for (int j = start; j < end; j++) { sum += a[j]; } if (sum > maxSum) { maxSum = sum; res = i; } } cout << res; return 0 ; }
42 外卖店优先级 解题日期:250219 解题用时:37min 题目来源:蓝桥杯真题 题目难度:中等 题目标签:2019,模拟,省赛
题意整理 “饱了么”外卖系统中维护着 N 家外卖店,编号 1 ∼ N。每家外卖店都有一个优先级,初始时 (0 时刻) 优先级都为 0。
每经过 1 个时间单位,如果外卖店没有订单,则优先级会减少 1,最低减到 0;而如果外卖店有订单,则优先级不减反加,每有一单优先级加 2。
如果某家外卖店某时刻优先级大于 5,则会被系统加入优先缓存中;如果优先级小于等于 3,则会被清除出优先缓存。
给定 T 时刻以内的 M 条订单信息,请你计算 T 时刻时有多少外卖店在优先缓存中?
解题思路 以时间为维度进行处理即可。
AC代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 #include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]) { int n,m,t; scanf ("%d %d %d" ,&n,&m,&t); int ts[100000 ], id[100000 ]; int book[100000 ]; int arr[100000 ]; int fit[100000 ]; int ret=0 ; for (int i=0 ;i<m;i++) { scanf ("%d %d" ,&ts[i],&id[i]); } for (int i=0 ;i<=t;i++) { for (int j=0 ;j<=n;j++) { book[j]=0 ; } for (int j=0 ;j<m;j++) { if (ts[j]==i) { arr[id[j]]+=2 ; book[id[j]]=1 ; } } for (int j=0 ;j<=n;j++) { if (arr[j]>0 &&book[j]==0 ) { arr[j]--; } if (fit[j]>0 &&book[j]==0 ) { fit[j]--; } } for (int j=0 ;j<=n;j++) { if (arr[j]>5 ) { fit[j]=arr[j]; } if (arr[j]<=3 ) { fit[j]=0 ; } } } for (int i=0 ;i<=n;i++) { if (fit[i]>=3 ) { ret++; } } printf ("%d" ,ret); return 0 ; }
43 特别的数 解题日期:250219 解题用时:3min 题目来源:蓝桥杯真题 题目难度:中等 题目标签:2019,暴力,枚举,省赛
题意整理 小明对数位中含有 2、0、1、9 的数字很感兴趣(不包括前导 0),在 1 到 40 中这样的数包括 1、2、9、10 至 32、39 和 40,共 28 个,他们的和是 574。
请问,在 1 到 n 中,所有这样的数的和是多少?
解题思路 直接判断即可。
AC代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include <iostream> using namespace std;bool isfit (int k) { while (k>0 ){ int temp=k%10 ; if (temp==2 ||temp==0 ||temp==1 ||temp==9 ){ return true ; } k/=10 ; } return false ; } int main () { int n; cin>>n; int count=0 ; for (int i=1 ;i<=n;i++){ if (isfit (i)){ count+=i; } } cout<<count; return 0 ; }
44 等差数列 解题日期:250219 解题用时:28min 题目来源:蓝桥杯真题 题目难度:中等 题目标签:2019,GCD
题意整理 数学老师给小明出了一道等差数列求和的题目。但是粗心的小明忘记了一部分的数列,只记得其中N个整数。现在给出这N个整数,小明想知道包含这N个整数的最短的等差数列有几项?
解题思路 先排序,找到最小的两个数之差,然后遍历所有的两个数字之差进行gcd操作即可。
AC代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #include <iostream> #include <algorithm> using namespace std;long long a[100001 ];int y (int a,int b) { if (b==0 )return a; else return y (b,a%b); } int main () { int n,i; cin>>n; for (int i=0 ;i<n;i++) cin>>a[i]; sort (a,a+n); int d=a[1 ]-a[0 ]; for (int i=2 ;i<n;i++) { d=y (d,a[i]-a[i-1 ]); } if (a[n-1 ]==a[0 ])cout<<n<<endl; else cout<<((a[n-1 ]-a[0 ])/d)+1 <<endl; return 0 ; }
45 解题日期:250219 解题用时: 题目来源:蓝桥杯真题 题目难度:中等 题目标签:2019,暴力,省赛
题意整理 图片旋转是对图片最简单的处理方式之一,在本题中,你需要对图片顺时针旋转 90 度。
我们用一个 n×m 的二维数组来表示一个图片,例如下面给出一个 3×4 的 图片的例子:
1 3 5 7
9 8 7 6
3 5 9 7
这个图片顺时针旋转 90 度后的图片如下:
3 9 1
5 8 3
9 7 5
7 6 7
给定初始图片,请计算旋转后的图片。
解题思路 注意二维数组开太大会爆内存!!先按照正常读入即可,然后输出的时候想一下先输出的是第一列、最后一行的数,依次类推得到输出的循环嵌套形式。
AC代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <iostream> using namespace std;int main () { int n,m; cin>>n>>m; int a[100 ][100 ]; for (int i=0 ;i<n;i++){ for (int j=0 ;j<m;j++){ cin>>a[i][j]; } } for (int j=0 ;j<m;j++){ for (int i=n-1 ;i>=0 ;i--){ cout<<a[i][j]; if (i==0 )cout<<endl; else cout<<" " ; } } return 0 ; }
46 大臣的旅费 解题日期:250219 解题用时:40min 题目来源:蓝桥杯真题 题目难度:中等 题目标签:2013,省赛,树形dp,搜索
题意整理 很久以前,T王国空前繁荣。为了更好地管理国家,王国修建了大量的快速路,用于连接首都和王国内的各大城市。为节省经费,T国的大臣们经过思考,制定了一套优秀的修建方案,使得任何一个大城市都能从首都直接或者通过其他大城市间接到达。同时,如果不重复经过大城市,从首都到达每个大城市的方案都是唯一的。
J是T国重要大臣,他巡查于各大城市之间,体察民情。所以,从一个城市马不停蹄地到另一个城市成了J最常做的事情。他有一个钱袋,用于存放往来城市间的路费。聪明的J发现,如果不在某个城市停下来修整,在连续行进过程中,他所花的路费与他已走过的距离有关,在走第x千米到第x+1千米这一千米中(x是整数),他花费的路费是x+10这么多。也就是说走1千米花费11,走2千米要花费23。
J大臣想知道:他从某一个城市出发,中间不休息,到达另一个城市,所有可能花费的路费中最多是多少呢?
解题思路
问题n个节点n-1一条边实际上是树,同时,要求求花最多的路费是多少,也即最长距离,转化为求树的直径
从任意一个节点开始,dfs第一遍求直径的一个端点u
从u节点开始,继续dfs ,求解距离当前节点最远的点,就是直径的另一个端点,继续u记录即可
按照题意根据距离计算ans即可
AC代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 #include <bits/stdc++.h> #define rep(i, a, b) for(int i = a; i < b; i++) using namespace std;const int N = 1e5 + 10 ;struct edge { int id, w; }; vector<edge> h[N]; int dis[N]; bool vis[N];int n;void dfs (int u, int distance) { dis[u] = distance; vis[u] = 1 ; for (auto x : h[u]) if (!vis[x.id]) dfs (x.id, distance + x.w); } int main () { cin >> n; rep (i, 0 , n - 1 ) { int a, b, w; cin >> a >> b >> w; h[a].push_back ({b, w}); h[b].push_back ({a, w}); } dfs (1 , 0 ); int u = 1 ; rep (i, 1 , n + 1 ) if (dis[i] > dis[u]) u = i; memset (vis, 0 , sizeof vis); dfs (u, 0 ); rep (i, 1 , n + 1 ) if (dis[i] > dis[u]) u = i; int s = dis[u]; printf ("%lld" , s * 10 + s * (s + 1ll ) / 2 ); return 0 ; }
47 翻硬币 解题日期:250219 解题用时:40min 题目来源:蓝桥杯真题 题目难度:中等 题目标签:2013,贪心,省赛
题意整理 小明正在玩一个”翻硬币”的游戏。
桌上放着排成一排的若干硬币。我们用 * 表示正面,用 o 表示反面(是小写字母,不是零)。
比如,可能情形是:** oo*** oooo;
如果同时翻转左边的两个硬币,则变为:oooo*** oooo。
现在小明的问题是:如果已知了初始状态和要达到的目标状态,每次只能同时翻转相邻的两个硬币,那么对特定的局面,最少要翻动多少次呢?
我们约定:把翻动相邻的两个硬币叫做一步操作。
解题思路 反向思维。遇到不匹配就反转这一个和下一个,按照顺序遍历即可。
AC代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include <iostream> #include <string.h> using namespace std;void swap (char x[1005 ],int i) { if (x[i]=='*' ){ x[i] = 'o' ; }else x[i] = '*' ; } int main () { char s[1000 ]; char x[1005 ]; cin>>s; cin>>x; int count = 0 ; int len = strlen (x); for (int i=0 ;i<len;i++){ if (s[i]!=x[i]){ swap (x,i); swap (x,i+1 ); count ++ ; } } cout<<count<<endl; return 0 ; }
48 核桃的数量 解题日期:250219 解题用时:3min 题目来源:蓝桥杯真题 题目难度:中等 题目标签:2013,省赛
题意整理 小张是软件项目经理,他带领 3 个开发组。工期紧,今天都在加班呢。为鼓舞士气,小张打算给每个组发一袋核桃(据传言能补脑)。他的要求是:
各组的核桃数量必须相同
各组内必须能平分核桃(当然是不能打碎的)
尽量提供满足 1,2 条件的最小数量(节约闹革命嘛)
解题思路 找三个数的最小公倍数。
AC代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <iostream> using namespace std;int main () { int a,b,c; cin>>a>>b>>c; int max=a; if (b>max)max=b; if (c>max)max=c; for (int i=max;;i++){ if ((i%a==0 )&&(i%b==0 )&&(i%c==0 )){ cout<<i; return 0 ; } } return 0 ; }
49 剪格子 解题日期:250219 解题用时:- 题目来源:蓝桥杯真题 题目难度:中等 题目标签:2013,省赛,搜索
题意整理 https://doc.shiyanlou.com/courses/uid1580206-20210202-1612250769606 我们沿着图中的红色线剪开,得到两个部分,每个部分的数字和都是60。
本题的要求就是请你编程判定:对给定的m×n的格子中的整数,是否可以分割为两个部分,使得这两个区域的数字和相等。如果存在多种解答,请输出包含左上角格子的那个区域包含的格子的最小数目。如果无法分割,则输出0。
解题思路 dfs+剪枝
AC代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #include <iostream> using namespace std;const int N = 15 ;int mp[N+5 ][N+5 ];int vis[N+5 ][N+5 ];int dir[4 ][2 ] = { {-1 ,0 },{1 ,0 },{0 ,-1 },{0 ,1 } };int sum, ans = 100000 ;int n, m;void dfs (int x, int y, int c, int s) { if (2 * s > sum)return ; if (2 * s == sum ) { if (c < ans && vis[0 ][0 ]) { ans = c; } return ; } vis[x][y] = 1 ; for (int i = 0 ; i < 4 ; i++) { int nx = x + dir[i][0 ]; int ny = y + dir[i][1 ]; if (nx >= 0 && nx < n && ny >= 0 && ny < m && !vis[nx][ny]) dfs (nx, ny, c + 1 , s+mp[x][y]); } vis[x][y] = 0 ; } int main () { scanf ("%d%d" , &m, &n); for (int i = 0 ; i < n; i++) for (int j = 0 ; j < m; j++) scanf ("%d" , &mp[i][j]),sum+=mp[i][j]; dfs (0 , 0 , 0 , 0 ); cout << (ans==100000 ?0 :ans); return 0 ; }
50 解题日期:250219 解题用时:- 题目来源:蓝桥杯真题 题目难度:中等 题目标签:2014,省赛,动态规划
题意整理 观察这个数列:
1 3 0 2 −1 1 −2 ⋯
这个数列中后一项总是比前一项增加 2 或者减少 3。
栋栋对这种数列很好奇,他想知道长度为 n 和为 s 而且后一项总是比前一项增加 a 或者减少 b 的整数数列可能有多少种呢?
解题思路 由于x是任意取的,题目可以简化为在总和为s 的情况下,一共包含n项 的数列中的数字只能是a或者-b,求方案总数。使用动态规划。
AC代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <iostream> using namespace std;const int N = 1010 , MOD = 1e8 + 7 ;int n, s, a, b;int f[N][N];int main () { cin >> n >> s >> a >> b; f[0 ][0 ] = 1 ; for (int i = 1 ; i < n; i++) for (int j = 0 ; j < n; j++) { f[i][j] = (f[i-1 ][((j-i*a)%n+n)%n] + f[i-1 ][((j+i*b)%n+n)%n]) % MOD; } cout << f[n-1 ][(s%n+n)%n] % MOD << endl; return 0 ; }