题意
来自 租酥雨
在接下来的 t t t 天时间里,有 n n n 个女孩子想要和 xxx 约会。第 i i i 个女孩子想要在 [ l i , r i ] [li,ri] [li,ri] 中的某一天和 xxx 约会,且约会后 xxx 会得到 p i p_i pi 的偷税值。在这里,我们保证 l i ≤ l i + 1 , r i ≤ r i + 1 li≤li+1,ri≤ri+1 li≤li+1,ri≤ri+1 。xxx 在第 i i i 天至多和 a i a_i ai 个女孩子约会,他希望你能帮他求出他能够获得的最大偷税值之和。
思路
正解需要用到霍尔定理,但是 tiandong123 并不需要这么麻烦,他只需要一个 multiset (喵踢set) 就好了。
首先可以发现,假如 p i p_i pi 大的能放,那么肯定优先放大的。
然后根据题中 l i ≤ l i + 1 , r i ≤ r i + 1 li≤li+1,ri≤ri+1 li≤li+1,ri≤ri+1 的奇妙限制,可以得到这样的贪心:按照读入的顺序遍历每一个区间,将所有区间的权值存在 multiset 中。当我现在加入一个区间 i i i ,那么在此之后不会再有区间能够匹配 l i l_i li 之前的某天,所以可以把 multiset 中的区间按权值从大到小取出来,匹配 l i l_i li 之前的天。然后向 multiset 中加入 p i p_i pi ,假如 multiset 中的区间个数多于 ∑ i = l i r i a i \sum_{i=l_i}^{r_i} a_i ∑i=liriai ,说明其中有些点无论如何也匹配不了了,这时就按权值从小到大取出区间丢掉。
换句话说, multiset 里存的就是能够匹配当前区间的天的最优的一些区间。
贪心好题,我想不到。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 3e5 + 10;
int n, m, a[N], ans, sum[N];
int le[N], ri[N], we[N], siz;
multiset<int> s;
signed main()
{
ios::sync_with_stdio(false);
cin >> m >> n;
for (int i = 1; i <= n; ++ i) cin >> a[i];
for (int i = 1; i <= n; ++ i) sum[i] = sum[i-1] + a[i];
le[0] = 1; ri[0] = 0;
for (int i = 1; i <= m; ++ i)
cin >> le[i] >> ri[i] >> we[i];
le[++m] = n+1; ri[m] = n;
for (int i = 1; i <= m; ++ i){
for (int j = le[i-1]; j < le[i]; ++ j){
while (a[j] && !s.empty()){
multiset<int>::iterator k = s.end();
k--;
ans += *k;
s.erase(k); siz--;
a[j]--;
}
}
s.insert(we[i]); siz++;
while (siz > sum[ri[i]]-sum[le[i]-1]){
multiset<int>::iterator k = s.begin();
s.erase(k); siz--;
}
}
cout << ans << endl;
return 0;
}