C++函数

一些在平时做算法题时不太会用到的函数

rotate函数

定义在<algorithm>头文件中,其作用是将范围内的元素进行循环移位:
rotate(first,middle,last)会将[first,middle)和[middle,last)范围内的元素互换位置,也就是左循环移位直到middle称为数组的第一个元素

例:
cf 2089 B2
给定长度为n的两个正整数数组a和b,保证a中的元素和小于b中的元素和
操作1:选择a中的一个元素,将其元素值减1
操作2:对于每一个下标i,将a[i]和b[i]同时减去min(a[i],b[i]),然后将数组a进行一次轮换
在最多执行k次1操作的情况下,最少需要进行几次操作2使得数组a中的元素全为0

首先考虑操作1执行次数为0的情况
因为数组a的元素和小于数组b的元素和,而且每次操作后两个数组的元素和是同时减去一个值的,从而该元素和大小关系保持不变,因此我们每一轮至少会有一个下标i,使得执行操作2后该位置变为0,最劣情况显然是每一轮只有一个变成0,因此答案上界是n
因为每次操作完后会循环右移,于是是一个环结构
但由于操作次数是有限的,从而可以破环成链,也就是将a和b都循环延长(复制一遍添加到末尾),同时,因为最多执行n次操作1,于是对于a[i](0<=i<n)只可能和b[j](i<=j<i+n)(a[i]每次向右移动,对应的b就是i+c)匹配(指匹配时a[i]在这轮操作后变为0)
可以仿照括号匹配的思路,a[i]作为左括号,对每个b[i]优先和左边第一个不为0的a[i]匹配(只是类似,本质是当前的b[j]一定是优先和左侧较近的a[i]进行操作)
于是从左到右枚举i,将每个不为0的a[i]入栈,然后b[i]不断和栈首的a[j]操作,直到存放元素a的栈为空或者b[i]=0,匹配的同时更新最大操作轮数,轮数实际就是i和j之间的距离i-j+1
现在再考虑操作1加入的情况
上面讨论的情况都是在操作1完成后的,并且是O(n)完成计算答案,同时操作1也是有界的,因此可以考虑二分答案(需要的轮次)
每次check,检查需要多少次操作1才能使轮数不超过mid,具体来说,每次我们都可以知道b[i]和a[j]匹配需要经过i-j+1轮,而当轮数超过mid时,我们就需要进行操作1,于是将当前的a[j]加到操作次数中
上面的算法已经足够了,但还可以进行一些优化
在循环数组操作中,可以使用rotate来优化复制数组的操作,这能保持数组的原始大小同时不引入其余数据,具体实现方式是用a[i]-b[i]来计算一个pre数组,将数组a和b都移动到pre数组最小的位置之后一位的位置(相当于把累计b[i]-a[i]最大的位置移动到最后,从而后续用b[i]去消耗栈中的元素时,有较多的可用值),这样能够保证在从0到n-1枚举完成后,一定能使得栈是空的

range和view

分别表示范围和视图

例如:

  1. ranges::count(range, value)
    功能:计算范围内等于指定值的元素数量
    返回:计数结果(整数)
    在这里用于检查特定范围内是否存在0元素

用range也可以略去对于数组范围的表述,例如:
int x = ranges::min_element(pre) - pre.begin();等价于int x = min_element(pre.begin(),pre.end()) - pre.begin();

  1. views::drop(n)
    功能:创建一个视图,跳过原始范围的前n个元素
    a | views::drop(2) 表示忽略 a 的前两个元素,只看剩余元素

  2. views::take(n)
    功能:创建一个视图,只包含原始范围的前n个元素
    a | views::take(2) 表示只考虑 a 的前两个元素

  3. a | views::drop(2)
    这是 C++20 范围库引入的管道操作符,用于组合视图和范围
    它将左侧的范围传递给右侧的视图适配器,生成一个新的视图

例:
cf 2085B
给定一个数组,每次操作选择数组中的区间,将这个区间替换为区间mex
问进行若干次这样的操作,能否使数组第一次长度为1时,数组元素是0

显然优先消去数组中的0,且最后一次操作是选择整个数组,因此考虑将数组划分为两部分,同时如果其中有0,就执行操作,否则可以跳过,这样能实现操作完成后数组长度不会先变成1

void solve() {
    int n;
    cin >> n;
    
    vector<int> a(n);
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    
    vector<array<int, 2>> ans;
    if (ranges::count(a | views::drop(2), 0)) {
        ans.push_back({2, n});
        n = 3;
    }
    if (ranges::count(a | views::take(2), 0)) {
        ans.push_back({0, 2});
        n--;
    }
    ans.push_back({0, n});
    cout << ans.size() << "\n";
    for (auto [l, r] : ans) {
        cout << l + 1 << " " << r << "\n";
    }
}

posted @ 2025-04-02 17:42  rdcamelot  阅读(23)  评论(0)    收藏  举报