蓝桥杯——2019第十届C/C++真题[省赛][B组](二)

简介: 蓝桥杯——2019第十届C/C++真题[省赛][B组]

完全二叉树的权值


image.png

思路:边输入边处理,我们容易知道,每一行的最后一个数的下标都是等于(2^n)-1,比如第二行的最后一个数等于2^2-1=3,第三行的最后一个数等于2^3-1=7,用deep表示当前深度,从当前这行的第一项加到最后一项然后和最大值max_sum比较。

代码:

#include<bits/stdc++.h>
using namespace std;
int Ai[100005];
int main(){
  int N;
  int deep = 1; //深度 
  int sum = 0; //每行的和 
  long long max_sum = -100000000000; //最大的和 
  int max_deep = 1;
  cin>>N;
  for(int i = 1; i <= N; ++i){
    cin>>Ai[i];
    sum += Ai[i];
    if(i == pow(2, deep) - 1){
      if(max_sum < sum){ //注意不要取等号,因为题目要最小的深度 
        max_deep = deep;
        max_sum = sum;
      }
      sum = 0;
      ++deep;
    }
  }
  cout<<max_deep<<endl;
  return 0;
}

等差数列


f398a904a41e4de9ac354f7af03bbb64.png

思路

等差数列的任意两项之差为公差的倍数。(a n − a 1 = ( n − 1 ) d , n ≥ 2 a_n-a_1=(n-1)d, n\ge2a

n −a 1 =(n−1)d,n≥2)拿样例来说,2, 6, 4, 10, 20,排序之后为2, 4, 6, 10, 20,与首项的差为2, 4, 8, 18。要使得等差数列最短就要使公差尽可能的大,就是要求差的最大公约数。n个数的最大公约数为求前两个的gcd,再用求出gcd与后面的数依次求。证明?不会 等差数列需要注意公差为0的情况   用到的知识1.等差数列的通项公式,注意公差为0的情况。2.欧几里得算法又称辗转相除法。

代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 100010;
int n;
int a[N];
int ans;
int gcd(int a, int b)
{
    return b ? gcd(b, a % b) : a;
}
int main()
{
    scanf("%d", &n);
    for (int i = 0; i < n; i++) scanf("%d", &a[i]);
    sort(a, a + n);
    for (int i = 1; i < n; i++)
        ans = gcd(ans, a[i] - a[0]);
    if (ans == 0) cout << n << endl;
    else cout << (a[n - 1] - a[0]) / ans + 1<< endl;
    return 0;
}

后缀表达式


image.png

思路: 分4种情况,

  1. 减号=0,没办法只能全部加起来
  2. 负数数目=0,排除了第1种情况,有减号,所以一定是其他数的和-最小的数
  3. 全为负数,这种最容易忽略,排除上述2种情况,所以只要有减号,一定是其他所有数的绝对值-最大负数的绝对值
  4. 其他情况,都是所有数的绝对值的和

代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
ll a[200005], sum = 0, mi = 1000000009;
int n, m, fu = 0;
bool cmp(int a, int b) { return a > b; }
int main() 
{
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n + m + 1; i++) 
    {
        scanf("%lld", &a[i]);
        if (a[i] < 0) fu++;
        sum += a[i];
        mi = min(mi, a[i]);
    }
    if (m == 0) printf("%lld\n", sum);
    else
    {
        if(fu == 0) printf("%lld\n", sum - mi - mi);
        else
        {
            if (fu == n + m + 1)  //***全是负数
            {
                sum = 0; mi = 1000000009;
                for (int i = 0; i < n + m + 1; ++i)
                {
                    sum += abs(a[i]);
                    mi = min(mi, abs(a[i]));
                }
                printf("%lld\n", sum - mi - mi);
            }
            else
            {
                sum = 0;
                for (int i = 0; i < n + m + 1; ++i) sum += abs(a[i]);
                printf("%lld\n", sum);
            }
        }
    }
    return 0;
}

灵能传输


image.png

840d87384c1242128f1040d1bfeffb5c.png

29023155a0d34153a8754c6a8f8720fb.png

思路:这题题量有点大。。。简单来说就是给定一组数,我们的目标是通过两种操作使得其中的绝对值最大的数达到最小,这两种操作是:

1、如果 a[i] > 0 并且 a[i - 1] 或者 a[i+1] 小于 0,我们可以将 a[i] 借给 i-1 元素和 i+1 元素,同时 a[i] 要变成 -a[i]。

2、如果 a[i] < 0 并且 a[i - 1] 或者 a[i+1] 大于 0,我们可以将 a[i-1] 和 a[i+1] 各借 abs(a[i]) 给 i 元素,之后 i 元素的值变成 -a[i] 也就是正数(a[i] 本身是小于 0 的),同时 a[i - 1] 和 a[i + 1] 要减掉 abs(a[i])。

我们考虑几种情况:

1、所有的数字都为正数或者都为负数,即所有的数字都同号。这种情况是没法借的,因为不符合操作要求,因此这种情况求出数组中绝对值最大的数即可。

2、对于 a[i],如果 a[i] 是正数,并且 a[i - 1] 和 a[i + 1] 至少有一个负数,那么我们的目标就是把那个绝对值最大的负数的绝对值缩小,这个时候如果另一边是正数,则需要考虑操作之后是否会产生新的绝对值更大的正数,比如现在有三个数:5 5 -6,如果我们把中间那个 5 按上面的操作 1 变换之后:10 -5 -1,绝对值最大数变成了 10,而之前是 6,显然不行。如果这三个数是这样的:1 5 -7,那么我们就可以按操作 1 变换:6 -5 -2,最大绝对值从 7 减小到了 6,是可行的。那么变换条件是什么呢?这里假设 a[i - 1] 是正数,a[i + 1] 是负数,那么条件可以写成:a[i - 1] + a[i] < abs(a[i + 1])。而如果 a[i - 1] 和 a[i + 1] 都是负数的时候,当两边的绝对值有一个大于 a[i] 时,就可以进行操作 1 变换。

3、对于 a[i] 是负数的时候,如果 a[i - 1] 是负数, a[i+1] 是正数,那么确保 a[i + 1] > abs(a[i] + a[i-1]),就可以进行操作 2 变换,如果两边都是正数则只要有一边的值大于 abs(a[i]) 时就可以进行操作 2 变换

代码

#include <cstdio>
#include <cmath>
#include <iostream>
using namespace std;
const int MAXN = 300010;
int nums[MAXN]; 
// 判断 a 和 b 是否异号 
bool judgeYi(int a, int b) {
  return a > 0 && b < 0 || a < 0 && b > 0;
} 
int main() {
  int T, n;
  cin >> T;
  while (T--) {
    cin >> n;
    // 标志负数和正数是否出现 
    bool hasNe = false, hasPo = false;
    int res = 0;
    for (int i = 0; i < n; i++) {
      scanf("%d", &nums[i]);
      if (nums[i] < 0) {
        hasNe = true;
      } else if (nums[i] > 0) {
        hasPo = true;
      }
    }
    // 如果数组中同时存在正负数,则判断能否进行操作 1 和 操作 2 
    if (hasNe && hasPo) {
      bool canNext;
      do {
        canNext = false;
        for (int i = 1; i < n - 1; i++) {
          // nums[i] 和 nums[i-1] 或 nums[i+1] 异号 
          if (judgeYi(nums[i], nums[i-1]) || judgeYi(nums[i], nums[i+1])) {
            if (nums[i] > 0) {
              // nums[i-1] 和 nums[i+1] 异号,
              // 这里的 if 和 else 可以合并,为了逻辑清晰,这里分开写 
              if (judgeYi(nums[i-1], nums[i+1])) {
                if ((nums[i-1] > 0 && abs(nums[i+1]) > nums[i-1] + nums[i]) || 
                  (nums[i+1] > 0 && abs(nums[i-1]) > nums[i+1] + nums[i])) {
                  nums[i+1] += nums[i];
                  nums[i-1] += nums[i];
                  nums[i] = -nums[i];
                  canNext = true;
                }
              } else { // nums[i-1] 和 nums[i+1] 同号,都 < 0 
                if (abs(nums[i-1]) > nums[i] || abs(nums[i+1]) > nums[i]) {
                  nums[i+1] += nums[i];
                  nums[i-1] += nums[i];
                  nums[i] = -nums[i];
                  canNext = true;
                } 
              } 
            } else if (nums[i] < 0) {
              // nums[i-1] 和 nums[i+1] 异号 
              if (judgeYi(nums[i-1], nums[i+1])) {
                if ((nums[i-1] > 0 && nums[i-1] > abs(nums[i+1] + nums[i])) || 
                  (nums[i+1] > 0 && nums[i+1] > abs(nums[i-1] + nums[i]))) {
                  nums[i+1] += nums[i];
                  nums[i-1] += nums[i];
                  nums[i] = -nums[i];
                  canNext = true;
                }
              } else { // nums[i-1] 和 nums[i+1] 同号,都 > 0 
                if (nums[i-1] > abs(nums[i]) || nums[i+1] > abs(nums[i])) {
                  nums[i+1] += nums[i];
                  nums[i-1] += nums[i];
                  nums[i] = -nums[i];
                  canNext = true;
                } 
              } 
            }
          } 
        }
      } while (canNext);
    }
    int t;
    // 求绝对值最大的值 
    for (int i = 0; i < n; i++) {
      res = max(res, abs(nums[i]));
    }
    cout << res << endl;
  }
  return 0;
}
相关文章
|
1月前
|
算法 测试技术 C++
【动态规划算法】蓝桥杯填充问题(C/C++)
【动态规划算法】蓝桥杯填充问题(C/C++)
|
1月前
|
人工智能 算法 BI
第十四届蓝桥杯省赛大学C组(C/C++)三国游戏
第十四届蓝桥杯省赛大学C组(C/C++)三国游戏
|
1月前
|
人工智能 C++
第十四届蓝桥杯省赛大学B组(C/C++)整数删除
第十四届蓝桥杯省赛大学B组(C/C++)整数删除
|
1月前
|
机器学习/深度学习 算法 关系型数据库
第十五届蓝桥杯C++B组省赛
第十五届蓝桥杯C++B组省赛
71 14
|
1月前
|
算法 C++
2022年第十三届蓝桥杯大赛C/C++语言B组省赛题解
2022年第十三届蓝桥杯大赛C/C++语言B组省赛题解
35 5
|
6月前
|
算法 测试技术 C++
小唐开始刷蓝桥(八)2013年第四届C/C++ B组蓝桥杯省赛真题
小唐开始刷蓝桥(八)2013年第四届C/C++ B组蓝桥杯省赛真题
|
6月前
|
算法 C++ 数据格式
小唐开始刷蓝桥(七)2014年第五届C/C++ B组蓝桥杯省赛真题
小唐开始刷蓝桥(七)2014年第五届C/C++ B组蓝桥杯省赛真题
|
6月前
|
算法 C++
小唐开始刷蓝桥(五)2016年第七届C/C++ B组蓝桥杯省赛真题
小唐开始刷蓝桥(五)2016年第七届C/C++ B组蓝桥杯省赛真题
|
6月前
|
算法 C++
小唐开始刷蓝桥(六)2015年第六届C/C++ B组蓝桥杯省赛真题
小唐开始刷蓝桥(六)2015年第六届C/C++ B组蓝桥杯省赛真题
|
6月前
|
数据安全/隐私保护 C++
小唐开始刷蓝桥(九)2012年第三届C/C++ B组蓝桥杯省赛真题
小唐开始刷蓝桥(九)2012年第三届C/C++ B组蓝桥杯省赛真题