1 条题解
-
0
我们来计算初始数组中每个单元格被多少个查询覆盖。可以证明,我们应该将较大的数组元素与较大的覆盖次数对应起来。更正式地说:假设 是一个数组,其第 个单元格中写的是覆盖第 个单元格的查询次数。假设 是初始数组。我们对这两个数组进行排序。可以证明,在这种情况下,答案可以通过以下公式计算:
我们来证明这个结论。考虑某两个下标 ,以及它们对应的元素 、(假设 ,)。这些元素对答案的贡献是 。如果我们交换 和 ,那么这些元素对答案的贡献变为 。我们来看以下差值:
$$a[i] \cdot b[j] + a[j] \cdot b[i] - a[i] \cdot b[i] - a[j] \cdot b[j] = b[j] \cdot (a[i] - a[j]) + b[i] \cdot (a[j] - a[i]) = (b[j] - b[i]) \cdot (a[i] - a[j]) \le 0 $$因此,交换两个元素会导致总结果不增。这意味着我们的排列是最优的。
现在我们需要足够快地计算出数组 。
为此,可以使用不同的支持区间修改的数据结构(线段树、笛卡尔树等)。但还有一种更简单的方法。
我们创建一个数组 。当有一个查询 时,我们将 增加 ,并将 减少 。通过这种巧妙的方式,我们将区间 内的所有元素都增加了 。处理完所有查询后,我们需要遍历数组 的每个元素。在这个遍历过程中,我们可以轻松计算出数组 的所有元素。
现在我们已经准备好得到最终答案。作者解法的时间复杂度为 。
#include <vector> #include <list> #include <map> #include <set> #include <deque> #include <stack> #include <queue> #include <algorithm> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cmath> #include <cstdlib> #include <memory.h> #include <ctime> using namespace std; #define ABS(a) ((a>0)?a:-(a)) #define MIN(a,b) ((a<b)?(a):(b)) #define MAX(a,b) ((a<b)?(b):(a)) #define FOR(i,a,n) for (int i=(a);i<(n);++i) #define FI(i,n) for (int i=0; i<(n); ++i) #define pnt pair <int, int> #define mp make_pair #define PI 3.14159265358979 #define MEMS(a,b) memset(a,b,sizeof(a)) #define LL long long #define U unsigned int a[200100]; int val[200100]; int b[200100]; int main() { int n,q; scanf("%d%d",&n,&q); FOR(i,0,n) scanf("%d",&a[i]); sort(a,a+n); FOR(i,0,q) { int l,r; scanf("%d%d",&l,&r); l--; r--; val[l]++; if (r<n-1) val[r+1]--; } int v=0; FOR(i,0,n) { v+=val[i]; b[i]=v; } sort(b,b+n); LL res=0; FOR(i,0,n) res+=(b[i]*1ll*a[i]); cout<<res<<endl; return 0; }
- 1
信息
- ID
- 6763
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 8
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者