Loading [MathJax]/jax/output/CommonHTML/jax.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >子数组,你让我拿什么爱你?

子数组,你让我拿什么爱你?

作者头像
ACM算法日常
发布于 2021-12-20 10:12:22
发布于 2021-12-20 10:12:22
32000
代码可运行
举报
文章被收录于专栏:ACM算法日常ACM算法日常
运行总次数:0
代码可运行

周赛的时候被第二题卡了一下,自己之前做过子数组的问题,可以用单调栈优化,比赛的时候也往这方面想了

思维有点难度,老是有 bug,突然发现过了一千多人,这才感觉到不对劲,这才发现数据范围看错了,遂改为暴力,又要掉分了,死在子数组上...

涉及知识点:模拟、子数组、单调栈、双指针、前缀和、二分查找、离散化

5952. 环和杆

给定一个字符串形如 R3G2B1,表示杆子 3, 2, 1 上分别有 R, G, B 颜色的圈

解析这个字符串,返回杆子上集齐了 rgb 三种颜色的杆子数量

题解

直接按字符解析,用哈希表套集合处理即可

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// cpp
class Solution {
public:
    int countPoints(string r) {
        unordered_map<int, set<int>> mp;
        for (int i = 0; i < r.size() - 1; i += 2) {
            int j = i + 1;
            if (!mp[r[j] - '0'].count(r[i])) mp[r[j] - '0'].insert(r[i]);
        }
        int ans = 0;
        for (auto& i: mp) {
            if (i.second.size() == 3) ans++;
        }
        return ans;
    }
};

5953. 子数组范围和

给定一个长度为 的数组,返回所有子数组最大值与最小值差的和数据规定

题解

这题比赛的时候想复杂了,直接爆炸数据范围不高,直接考虑 的做法

可以固定左端点,枚举右端点,然后维护最大最小值即可

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// cpp
class Solution {
public:
    long long subArrayRanges(vector<int>& nums) {
        typedef long long LL;
        int n = nums.size();
        LL ans = 0;
        for (int i = 0; i < n; ++i) {
            LL maxx = nums[i], minn = nums[i];
            for (int j = i + 1; j < n; ++j) {
                maxx = max(maxx, 1LL * nums[j]);
                minn = min(minn, 1LL * nums[j]);
                ans += maxx - minn;
            }
        }
        return ans;
    }
};

如果数据范围放大到 ,需要考虑 的做法

我们需要计算出每个元素 nums[i] 作为最大值、最小值所管辖的区间

以最大值为例,我们定义 dp[i] 表示到 i 为止最大值的和,我们需要用单调栈找到 i 左边第一个大于 nums[i] 的位置 j,然后可以状态转移方程 dp[i] = (j - i) * nums[i] + dp[j],最小值同理

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// cpp
class Solution {
public:
    long long subArrayRanges(vector<int>& nums) {
        typedef long long LL;
        int n = nums.size();
        vector<LL> maxx(n + 1), minn(n + 1);
        vector<int> lse(n + 1, 0), lge(n + 1, 0);
        stack<int> stk;
        for (int i = n; i >= 1; --i) {
            while (!stk.empty() && nums[stk.top() - 1] < nums[i - 1]) {
                lge[stk.top()] = i;
                stk.pop();
            }
            stk.push(i);
        }
        while (!stk.empty()) stk.pop();
        for (int i = n; i >= 1; --i) {
            while (!stk.empty() && nums[stk.top() - 1] > nums[i - 1]) {
                lse[stk.top()] = i;
                stk.pop();
            }
            stk.push(i);
        }
        LL ans = 0;
        for (int i = 1; i <= n; ++i) {
            //cout << i << ' ' << lge[i] << ' ' << lse[i] << endl;
            int j = lge[i];
            maxx[i] = 1LL * (i - j) * nums[i - 1] + maxx[j];
            j = lse[i];
            minn[i] = 1LL * (i - j) * nums[i - 1] + minn[j];
            ans += maxx[i] - minn[i];
        }
        return ans;
    }
};

5954. 给植物浇水 II

数轴上分布了 个植物, 从两头开始给植物浇水,每个人水桶的容量分别为

如果植物所需要的水量超过当前水桶的量,他们需要补水,计算浇灌结束所有植物的时候,他们补水的次数

数据规定

题解

两个指针从数组两头扫描,模拟浇灌的过程,时间复杂度

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// cpp
class Solution {
public:
    int minimumRefill(vector<int>& p, int ca, int cb) {
        int n = p.size();
        int i = 0, j = n - 1, a = ca, b = cb, ans = 0;
        while (i <= j) {
            if (i == j) {
                if (a == b) {
                    if (a < p[i]) a = ca, ans++;
                    a -= p[i++];
                }
                else if (a < b) {
                    if (b < p[j]) b = cb, ans++;
                    b -= p[j--];
                }
                else {
                    if (a < p[i]) a = ca, ans++;
                    a -= p[i++];
                }
            }
            else {
                if (a < p[i]) ans++, a = ca;
                a -= p[i++];
                if (b < p[j]) ans++, b = cb;
                b -= p[j--];
            }
        }
        return ans;
    }
};

5955. 摘水果

给定一个坐标轴,上面分布了 个水果,每个水果有自己的坐标 和价值 你位于 ,每次移动一单位耗费一点体力值,你一共有 体力,计算可以获得的最大水果价值数据规定

题解

考虑从 出发,向右走 ,那么向左走 ,轨迹为 ,我们只要计算该区间的最大价值即可考虑从 出发,向左走 ,那么向右走 ,轨迹为 ,我们只要计算该区间的最大价值即可预处理前缀和,在数轴不那么大的情况下,我们可以直接计算整个数轴的前缀和,时间复杂度

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// cpp
class Solution {
public:
    int maxTotalFruits(vector<vector<int>>& f, int st, int k) {
        int n = f.size();
        int max_r = (*(max_element(f.begin(), f.end(), [&](const vector<int>& a, const vector<int>& b) {
            return a[0] < b[0];
        })))[0] + 1;
        //cout << max_r << endl;
        vector<int> sum(max_r + 1);
        for (int i = 0; i < n; ++i) {
            sum[f[i][0] + 1] += f[i][1];
        }
        for (int i = 1; i <= max_r; ++i) {
            sum[i] += sum[i - 1];
        }
        st++;
        int ans = 0;
        for (int x = k; x >= 0; --x) {
            int y = (k - x) / 2;
            int L1 = max(1, st - y), R1 = min(max_r, st + x);
            int L2 = max(1, st - x), R2 = min(max_r, st + y);
            if (L1 > R1 && L2 > R2) continue;
            if (L1 <= R1) ans = max(ans, sum[R1] - sum[L1 - 1]);
            if (L2 <= R2) ans = max(ans, sum[R2] - sum[L2 - 1]);
        }
        return ans;
    }
};

如果数轴特别大,需要离散化记录前缀和,否则时间和空间都会爆炸,时间复杂度为

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// cpp
class Solution {
public:
    int maxTotalFruits(vector<vector<int>>& f, int st, int k) {
        int n = f.size();
        vector<int> sum;
        sum.push_back(0);
        for (int i = 1; i <= n; ++i) {
            sum.push_back(f[i - 1][1] + sum[i - 1]);
        }
        vector<int> pos;
        for (auto& i: f) pos.push_back(i[0]);
        int ans = 0;
        for (int x = k; x >= 0; --x) {
            int y = (k - x) / 2;
            int L = st - y, R = st + x;
            auto l = lower_bound(pos.begin(), pos.end(), L) - pos.begin();
            auto r = upper_bound(pos.begin(), pos.end(), R) - pos.begin();
            ans = max(ans, sum[r] - sum[l]);
            L = st - x, R = st + y;
            l = lower_bound(pos.begin(), pos.end(), L) - pos.begin();
            r = upper_bound(pos.begin(), pos.end(), R) - pos.begin();
            ans = max(ans, sum[r] - sum[l]);
        }
        return ans;
    }
};
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-12-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 ACM算法日常 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
LeetCode 第 201 场周赛(304/5614,前5.42%)
全国排名: 304 / 5614,5.42%;全球排名: 956 / 15616,6.12%
Michael阿明
2021/02/19
4260
Codeforces 1107G(dp)
Vasya有n个题目可选,每道题难度为d[i],买这道题要花的钱为c[i]。他最后一定要选连续的一堆题买过来(也可以不选),即一个区间。然后每道题目他能卖a块钱(注意这是个定值,每道都是a元),这样他赚了一些钱吧,还没完,还要扣点钱,即gap,注意这个gap,之后我们要多次提到。gap的具体定义见题目中的数学公式,口述会凌乱。
ACM算法日常
2019/04/25
5160
Codeforces 1107G(dp)
LeetCode 1630. 等差子数组
如果一个数列由至少两个元素组成,且每两个连续元素之间的差值都相同,那么这个序列就是 等差数列 。更正式地,数列 s 是等差数列,只需要满足:对于每个有效的 i , s[i+1] - s[i] == s[1] - s[0] 都成立。
Michael阿明
2021/02/19
3370
NOI 系列真题练习笔记
NOIP 前开始做做真题,虽然每年都风格迥异,不过感受一下 OI 风格的题目还是有一定意义的。
Clouder0
2022/09/23
8810
上分掉分,不过一念之间罢
现在可以在空地放水桶,位置 i 的水桶可以服务 i - 1, i + 1 位置的房屋
ACM算法日常
2021/12/06
4860
算法学习笔记-栈(stack)
这题跟上面的题目是一模一样的,最少添加就是有多少括号没有对象,,没有对象的括号都会留在栈中,有的都会出栈,所以就是求栈的大小;
买唯送忧
2021/05/23
4190
Codeforces Round #549(div1)简析
正解貌似有分四种情况什么的,我做时是发现各个起点其实都等价的,所以随便选一个起点,再暴举终点以暴举答案,更新即可。
ACM算法日常
2019/04/25
4160
[OI题库]八月提高模拟题解
具体地,将该点插入单调栈时,只会改变栈顶位置和插入点的值。记录原栈顶位置、插入点更改前的值,即可在回溯时撤销。
Clouder0
2022/09/23
2830
LeetCode 581. 最短无序连续子数组(排序&单调栈)
给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。
Michael阿明
2020/07/13
5990
LeetCode 581. 最短无序连续子数组(排序&单调栈)
LeetCode周赛2021年5月9日
太久不写代码了 第一次有空 做LeetCode周赛 不是 下标越界 就是 暴力超时
韩旭051
2021/05/11
5280
LeetCode周赛2021年5月9日
NOIP2020 前练习笔记
给一棵树,每个点权值为 w_i,需要将节点分组。 分组要求:每个组内的点,两两不存在祖先——后代关系。 每个组的代价是组内的最大值,求最小的总代价。
Clouder0
2022/09/23
5340
蔚来的题,偏思维,有点意思!
蔚来汽车联名力扣周赛的题目涉及的算法都很常见,但是都带了一点思维,作为头脑风暴是个不错的选择。
ACM算法日常
2021/12/28
7580
从二进制枚举 follow up 到二分图判定,有点意思
不过我在评论区看到有人提到了 T4 对应的 follow-up 题,是 codeforces div2 的 D 题,涉及到了图论建模和二分图判定,一起来看一看吧
ACM算法日常
2022/02/10
3890
Leetcode | 第A节:数组综合题(1)
在这一节我们开始更多关注数组和字符串的一些题目。事实上不仅仅是我们,官方也很难将这两个类别的题目,从算法或者数据结构的角度进行区分。毕竟很多很多的算法题都需要依赖数组,所有的字符串的题目不管用什么方法去做,它也都是字符串相关的问题。因此,我们在一开始介绍这些的时候,也会大概率与之前已经介绍的一些内容相结合。
学弱猹
2021/08/06
5070
力扣209. 长度最小的子数组
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
ccf19881030
2023/05/09
2490
维格表联名的思维场,想通了算法才简单
这场周赛由 vika 维格联名,第二题和第四题都比较偏思维,想通了就很简单,想不通就会被罚坐
ACM算法日常
2022/02/10
2900
【算法/训练】:单调队列&&单调栈
当01100符合时,窗口外面的肯定也符合要求 注意:循环截止条件为 right < n - 1.
IsLand1314
2024/10/15
1330
【算法/训练】:单调队列&&单调栈
loj#6041. 「雅礼集训 2017 Day7」事情的相似度(SAM set启发式合并 二维数点)
只会后缀数组+暴躁莫队套set\(n \sqrt{n} \log n\)但绝对跑不过去。
attack
2019/04/01
5850
超超超高频面试题,快来混个脸熟(一)
此份试题来自民间面经、code top 网站以及部分官方渠道,命中率超高,可以混个脸熟
ACM算法日常
2021/09/07
2510
腾讯9.5第二批后端笔试牛客大佬全AC记录
来自小海胆胆 腾讯2022届第二次笔试 牛牛的数链们 难度:2星 知识点:链表,模拟 模拟一下即可 classSolution { public: /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param a ListNode类vector 指向这些数链的开头 * <a href="/profile/547241" data-card-uid="547241" class="" ta
opencode
2022/12/26
4660
腾讯9.5第二批后端笔试牛客大佬全AC记录
相关推荐
LeetCode 第 201 场周赛(304/5614,前5.42%)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验