差分思想 审核通过

Wind_Rises 砂糖老师 2024-11-05 14:30:14 4

注意事项

1.不能使用暴力计算cnt,否则时间复杂度是O()。

2.注意开long long,否则会爆int。

3.注意数据范围,否则可能会数组越界。

解题思路

1.统计每个元素在查询中的“权重”:

如果一个元素频繁出现在多个查询区间内,那么它的“权重”较高,意味着在最大化总和时,我们应该将该元素设为一个大的数。

2.通过差分数组快速计算权重:

每次查询增加一个区间 的和。使用差分数组可以高效地标记每个查询区间的左右边界,得到每个元素被包含的总次数(权重)。

3.重新排列元素使得总和最大化:

将数组 中的数值降序排列,并将权重数组 也降序排列。这样大数与高权重匹配,可以得到最大的和。

AC代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long

const int N = 1e6 + 5;
int a[N] = {};          // 存储原数组 A
ll cnt[N] = {};         // 存储每个位置的权重(出现次数)
ll diff[N] = {};        // 差分数组,帮助快速计算 cnt
int n, m;

int main() {
    // 1. 读取输入的 n 和数组 A
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];

    // 2. 读取查询次数 m 和每个查询的左右端点 L 和 R
    cin >> m;
    int l, r;
    while (m--) {
        cin >> l >> r;
        diff[l]++;             // 差分数组标记左端点
        diff[r + 1]--;         // 差分数组标记右端点+1
    }

    // 3. 计算权重数组 cnt(每个元素在所有查询中的出现次数)
    for (int i = 1; i <= n; i++) {
        cnt[i] = cnt[i - 1] + diff[i];
    }

    // 4. 计算原数组的总和 sum1
    ll sum1 = 0;
    for (int i = 1; i <= n; i++) sum1 += a[i] * cnt[i];

    // 5. 排序后计算最优结果的总和 sum2
    sort(a + 1, a + 1 + n);    // 数组 A 排序
    sort(cnt + 1, cnt + 1 + n); // 权重数组 cnt 排序
    ll sum2 = 0;
    for (int i = 1; i <= n; i++) sum2 += a[i] * cnt[i];

    // 6. 输出答案,即增量 sum2 - sum1
    cout << sum2 - sum1 << endl;
    return 0;
}

{{ vote && vote.total.up }}

共 2 条回复

Wind_Rises 砂糖老师

@CPP 偷懒ing

CPP 刷题王

时间复杂度那 O 应为 。个人习惯把所有英文字母与汉字之间打上空格。