第 9 个测试点开了 O2 就过了,不开 O2 就 TLE

P1886 滑动窗口 /【模板】单调队列

Zaoly @ 2023-01-09 11:57:37

9 个测试点开了 O2 优化就过了,不开 O2 就 TLE。那么,这个程序有改进空间,使得在不开 O2 的情况下也能过吗?

语言:C++

我的思路是:用多重集合 multiset 记录每个区间内的数字。每次滑动,都从多重集合中删除一个左边少掉的数(使用 erase(find()) 实现,如果直接 erase 值的话,会删除所有相等的元素),并添加右边多出的数。通过 begin() 获取最小值,通过 rbegin() 获取最大值。

#include <iostream>
#include <set>

using namespace std;

int main()
{
    int n = 0, width = 0, * arr = nullptr, i = 0;
    int* mins = nullptr, * maxes = nullptr;
    multiset<int> nums;
    cin >> n >> width;
    arr = new int[n];
    for (; i < n; ++i)
        cin >> arr[i];
    for (i = 0; i < width; ++i)
        nums.insert(arr[i]);
    mins = new int[n - width + 1];
    maxes = new int[n - width + 1];
    mins[0] = *nums.begin();
    maxes[0] = *nums.rbegin();
    for (i = 1; i <= n - width; ++i)
    {
        nums.erase(nums.find(arr[i - 1]));
        nums.insert(arr[i - 1 + width]);
        mins[i] = *nums.begin();
        maxes[i] = *nums.rbegin();
    }
    for (i = 0; i <= n - width; ++i)
        cout << mins[i] << ' ';
    cout.put('\n');
    for (i = 0; i <= n - width; ++i)
        cout << maxes[i] << ' ';
    cout << endl;
    delete[] arr;
    delete[] mins;
    delete[] maxes;
    return 0;
}

注:亲测 ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr); 不可行。


by 0x3F @ 2023-01-09 12:04:34

错误的,不仅复杂度错误而且常数还大


by Shunpower @ 2023-01-09 12:04:38

您的复杂度如果我没记错 multiset 复杂度的话应该是 O(n\log V) 的。

辅之以 multiset 的巨大常数是非常容易 TLE 的,建议您学习时间复杂度 O(n) 的单调队列解决这道题。


by OldDriverTree @ 2023-01-09 12:06:08

@Zaoly 复杂度本来就是错的,建议学习单调队列做法


by Cerisier @ 2023-01-09 12:33:54

建议学习分块做法


by Zaoly @ 2023-01-09 12:37:26

@0x3F 复杂度大能理解,但是我不能理解常数大是什么意思。是什么常数大?


by Zaoly @ 2023-01-09 12:37:38

@Zealous_YH 复杂度大能理解,但是我不能理解常数大是什么意思。是什么常数大?


by 0x3F @ 2023-01-09 13:12:56

@Zaoly stl 常数本来就大

还有 O2 可以减小 stl 的常数


|