牛客——前缀和前缀最大值,前缀平方和序列,好数组

前缀和前缀最大值

题目描述

登录—专业IT笔试面试备考平台_牛客网

运行代码

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int n;
    cin >> n;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    vector<int> pre(n + 1);
    vector<vector<int>> sum(n + 1, vector<int>(101));
    vector<int> presum(n + 1);
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= 100; j++) {
            sum[i][j] = sum[i - 1][j];
        }
        if (a[i] > 0) {
            pre[i] = pre[i - 1] + 1;
        } else {
            pre[i] = pre[i - 1];
        }
        if (a[i] > 0) {
            sum[i][a[i]]++;
        }
        presum[i] = presum[i - 1] + a[i];
    }
    int q;
    cin >> q;
    while (q--) {
        int l, r;
        cin >> l >> r;
        int cnt = 0;
        int lrsum = presum[r] - presum[l - 1];
        int res = 0;
        for (int i = 100; i >= 1; i--) {
            int temp = sum[r][i] - sum[l - 1][i];
            if (temp && lrsum > 0) {
                if (lrsum - i * temp <= 0) {
                    cnt += (lrsum + i - 1) / i;
                    break;
                } else {
                    cnt += temp;
                    lrsum -= i * temp;
                }
            }
        }
        int ans = pre[r] - pre[l - 1] - cnt + 1;
        cout << ans << "\n";
    }
    return 0;
}

代码思路

一、整体思路

  1. 首先读取输入的整数 n,表示序列 b 的长度。
  2. 接着读取 n 个整数存入 vector<int> a(n + 1)(这里命名为 a,实际上代表序列 b)。
  3. 通过遍历序列 b,计算并存储一些辅助信息,包括前缀和数组 pre、二维数组 sum 和前缀和数组 presum
  4. 然后读取整数 q,表示询问次数。
  5. 对于每次询问,读取两个整数 l 和 r,表示查询区间的左右边界。在查询区间内进行计算,得到该区间序列的 B类价值并输出。

二、具体原理

  1. 输入输出同步和流绑定的设置

    • ios_base::sync_with_stdio(false);:取消 C++ 标准流(std::cinstd::cout 等)与 C 标准流(stdinstdout 等)的同步,这样可以提高输入输出的效率。
    • cin.tie(nullptr); cout.tie(nullptr);:解除 std::cin 和 std::cout 的绑定,进一步提高效率。
  2. 读取输入和存储序列:读取 n 后,使用循环读取 n 个整数存入 vector<int> a(n + 1)

  3. 计算辅助信息

    • 前缀和数组 pre:原本在给定的问题背景下不太明确其确切用途,但从代码逻辑看,可能与某些计数或统计有关,不过在这里没有完全体现出与问题中定义的 AA 类价值和 BB 类价值的直接联系。如果当前元素 a[i] 大于 0,那么 pre[i] = pre[i - 1] + 1,否则 pre[i] = pre[i - 1]
    • 二维数组 sumsum[i][j] 表示前 i 个元素中值为 j 的元素的个数。初始化时,对于每个 jsum[i][j] = sum[i - 1][j],即先继承上一个位置的值。如果当前元素 a[i] 大于 0,那么 sum[i][a[i]]++
    • 前缀和数组 presumpresum[i] 表示前 i 个元素的和。通过 presum[i] = presum[i - 1] + a[i] 计算得到。
  4. 处理查询:对于每次查询的区间 [l, r]

    • 最后计算结果 ans = pre[r] - pre[l - 1] - cnt + 1,并输出。然而,从给定的问题描述来看,不太清楚这个结果与问题中所求的序列 b[l::r] 的 B 类价值的具体对应关系。
    • 然后从大到小遍历 100 到 1,对于每个值 i
      • 计算区间内值为 i 的元素个数 temp = sum[r][i] - sum[l - 1][i]
      • 如果 temp 不为 0 且 lrsum 大于 0,进行如下判断:
        • 如果 lrsum - i * temp <= 0,说明可以用值为 i 的元素以及可能更小的值的元素来填满区间,此时 cnt += (lrsum + i - 1) / i(向上取整),并跳出循环。
        • 否则,用值为 i 的元素填充部分区间,cnt += temp,同时更新 lrsum,即 lrsum -= i * temp
    • 首先计算查询区间的元素和 lrsum = presum[r] - presum[l - 1]

前缀平方和序列

题目描述

登录—专业IT笔试面试备考平台_牛客网

运行代码

#include <iostream>
#include <vector>
#define int long long
using namespace std;
const int N = 2e5 + 10;
const int mod = 1e9 + 7;

int FN(int a, int b) {
    int res = 1;
    while (b) {
        if (b & 1) res = res * a % mod;
        b >>= 1;
        a = a * a % mod;
    }
    return res;
}

int comb(int n, int m) {
    if (n < m || n < 0 || m < 0) return 0;
    int res = 1;
    for (int i = 1, j = n; i <= m; i++, j--) {
        res = res * j % mod;
        res = res *FN(i, mod - 2) % mod;
    }
    return res;
}

signed main() {
    int n, x;
    cin >> n >> x;
    vector<int> p;
    for (int i = 1; i * i <= x; i++) 
        p.push_back(i * i);
    int m = p.size();
    int res = comb(m, n);
    cout << res <<endl;
    return 0;
}

代码思路

一、整体思路

  1. 首先从输入中获取序列长度 n 和上限值 x
  2. 找到所有不超过 x 的平方数,并存储在一个向量 p 中。
  3. 计算从这些平方数中选取 n 个的组合数,作为满足条件的前缀平方序列的个数。

二、具体原理

  1. 快速幂函数 FN 部分:

    • 这个函数用于计算 a 的 b 次幂对 mod 取模的结果。
    • 使用位运算的方式实现快速幂算法,当 b 的二进制表示中的某一位为 1 时,将当前的 a 的幂累乘到结果中,同时不断更新 a 为 a 的平方,b 右移一位,直到 b 变为 0
  2. 组合数计算函数 comb 部分:

    • 这个函数用于计算从 n 个不同元素中选取 m 个的组合数。
    • 首先判断输入的合法性,如果 n < m 或者 nm 为负数,则返回 0
    • 然后通过递推的方式计算组合数,先将 n 开始的 m 个数累乘到结果中,同时对于每一步乘积,都乘以当前步数的逆元(即 FN(i, mod - 2),利用费马小定理计算逆元),最后得到组合数对 mod 取模的结果。
  3. 主函数部分:

    • 读取输入的 n 和 x
    • 通过遍历找到所有不超过 x 的平方数,并存储在向量 p 中,其大小为 m
    • 调用 comb 函数计算从 m 个平方数中选取 n 个的组合数,作为满足条件的前缀平方序列的个数,并输出结果。

总的来说,这个算法的原理是通过计算不超过给定上限 x 的平方数的组合数,来确定满足长度为 n 且前缀和都是平方数且不超过 x 的序列的个数。因为满足条件的序列的前缀和必须是不超过 x 的平方数,所以可以先找出这些平方数,然后计算从这些平方数中选取 n 个的组合数,即为所求的结果。

好数组

题目描述

登录—专业IT笔试面试备考平台_牛客网

运行代码

#include <iostream>

int main() {
    int n;
    std::cin >> n;
    for (int i = 0; i < n; ++i) {
        int x;
        std::cin >> x;
        if (x == 0) {
            std::cout << "NO";
            return 0;
        }
    }
    std::cout << "YES";
    return 0;
}

代码思路

一、整体思路

  1. 首先从输入中获取数组的长度 n
  2. 然后依次读取 n 个整数作为数组的元素。
  3. 在读取过程中检查是否存在元素为 0,如果有则直接输出 "NO" 并结束程序。
  4. 如果所有元素都不为 0,则输出 "YES"

二、具体原理

  1. 输入数据部分:使用 std::cin >> n 读取数组的长度 n。接着使用一个循环,每次读取一个整数 x,代表数组中的一个元素。

  2. 检查元素部分:在循环中,检查每个读取的元素 x 是否为 0。如果某个元素为 0,根据题目要求,存在两个相同的元素(都是 0),它们的差的绝对值为 0,而乘积也为 0,不满足 “任意两个元素的差的绝对值都小于这两个元素的乘积” 这个条件,所以输出 "NO" 并返回。

  3. 输出结果部分:如果循环结束后都没有发现元素为 0,说明可能满足好数组的条件,输出 "YES"

这个代码的原理是通过逐个检查输入数组中的元素是否为 0,来快速判断是否不满足好数组的条件。如果没有找到 0 元素,就假设可能满足好数组的条件并输出 "YES"

题目要求:给定一个二叉树和一个整数target,找出所有从根节点到叶子节点路径之和等于target的路径。 解题思路:可以使用深度优先搜索(DFS)的方法来解决该问题。首先定义一个辅助函数来进行递归搜索,该辅助函数的参数包括当前节点、当前路径、当前路径的和以及目标和。在搜索过程中,需要维护一个数组来保存当前节点到根节点的路径。搜索过程如下: 1. 如果当前节点为空,则返回。 2. 将当前节点的值添加到当前路径中。 3. 将当前节点的值累加到当前路径的和中。 4. 如果当前节点是叶子节点,且当前路径的和等于目标和,则将当前路径添加到结果中。 5. 递归地搜索当前节点的左子树和右子树,并传递更新后的当前路径和当前路径的和。 最后,在主函数中调用辅助函数,并返回结果即可。 以下是题目的完整代码实现: ```python class TreeNode: def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = right def pathSum(root, target): def dfs(node, path, path_sum, target, res): if not node: return path.append(node.val) path_sum += node.val if not node.left and not node.right: # 当前节点是叶子节点 if path_sum == target: res.append(path[:]) # 注意需要复制一份path,否则会出现问题 dfs(node.left, path, path_sum, target, res) dfs(node.right, path, path_sum, target, res) path.pop() # 回溯到父节点,去掉当前节点 path_sum -= node.val res = [] dfs(root, [], 0, target, res) return res ``` 这样就能找出所有满足路径和等于目标和的路径了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

筱姌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值