1452E Two Editorials(贪心+预处理)
Educational Codeforces Round 98 (Rated for Div. 2)
E. Two Editorials
题意:一场竞赛有 n n n 道题目,赛后 2 2 2 位讲师每位分别需要选择讲解连续 k k k 题的题解, 2 2 2 位讲师讲的题目可以重复。现在有 m m m 个选手听题解,每位选手感兴趣的题目区间为 [ l i , r i ] [l_i, r_i] [li,ri],每位选手只能选择听 1 1 1 位讲师的题解,若该讲师讲了 x x x 道自己感兴趣的题目,则定义该选手的满意值为 a i a_i ai。问这 2 2 2 位讲师的所有选择中,可能得到的 ∑ a i \sum a_i ∑ai 最大值是多少。
范围: 1 ≤ n , m ≤ 2000 , 1 ≤ k ≤ n , 1 ≤ l i ≤ r i ≤ n 1 \le n, m \le 2000,~1 \le k \le n,~ 1 \le l_i \le r_i \le n 1≤n,m≤2000, 1≤k≤n, 1≤li≤ri≤n。
分析: 对于两个区间来说,他们的交集大小 l e n len len 可以通过他们中心点之间的距离 d i s t dist dist 进行反映, d i s t dist dist 越小, l e n len len 非降。我们可以按照中心点的大小对这些区间进行排序,那么根据贪心的思想,显然我们可以把排序后的区间分成前后两个部分,一个讲师负责前面的部分,另一个讲师负责后面的部分。
如果直接按照上面的思路进行枚举两个讲师的区间以及大区间的分隔位置,时间复杂度为 O ( n 2 m ) O(n^2m) O(n2m),还需要进行优化,考虑进行预处理。我们可以从后往前预处理出 s u f f i x suffix suffix 数组, s u f f i x [ i ] suffix[i] suffix[i] 表示所有 j ∈ [ i , m ] j \in [i, m] j∈[i,m] 选手都听第 2 2 2 个讲师讲题能得到的 ∑ a j \sum a_j ∑aj 最大值。那么现在我们只需要枚举第 1 1 1 个讲师的区间以及大区间的分隔位置,利用 s u f f i x suffix suffix 更新答案,时间复杂度为 O ( n m ) O(nm) O(nm)。
Code:
#include <bits/stdc++.h>
#define int long long
#define double long double
using namespace std;
inline int read()
{
int s = 0, w = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
s = s * 10 + ch - '0', ch = getchar();
return s * w;
}
const int MAXN = 2000 + 10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const double eps = 1e-9;
const double PI = acos(-1.0);
int n, m, k;
struct Node
{
int l, r;
bool operator < (const Node &other) const
{
return l + r < other.l + other.r;
}
} nodes[MAXN];
int suffix[MAXN];
signed main()
{
n = read(), m = read(), k = read();
for (int i = 0; i < m; i++)
{
nodes[i].l = read(), nodes[i].r = read();
}
sort(nodes, nodes + m);
for (int i = 0; i < n - k + 1; i++)
{
int sum = 0;
for (int j = m - 1; j >= 0; j--)
{
sum += max(0ll, min(i + k, nodes[j].r) - max(i, nodes[j].l - 1));
suffix[j] = max(suffix[j], sum);
}
}
int ans = 0;
for (int i = 0; i < n - k + 1; i++)
{
int sum = 0;
for (int j = 0; j < m; j++)
{
sum += max(0ll, min(i + k, nodes[j].r) - max(i, nodes[j].l - 1));
ans = max(ans, sum + suffix[j + 1]);
}
}
cout << ans << endl;
return 0;
}
【END】感谢观看