求两个窗口的贡献,对第一个窗口
[
i
−
k
+
1
,
i
]
[i-k+1,i]
[i−k+1,i],遍历
[
l
i
,
r
i
]
[l_i,r_i]
[li,ri],求出第一个窗口的贡献,考虑第二个窗口的附加贡献,为求附加贡献,用差分的方法,假设第一个窗口覆盖区间长度
w
w
w,那么仅当第二个区间覆盖长度
>
w
\gt w
>w时需要考虑附加贡献。如果从小到大枚举第二个窗口的右端点,每滑动一个需要考虑新增加和删除的贡献,这些贡献源于
[
l
i
,
r
i
]
[l_i,r_i]
[li,ri],可以直接考虑
[
l
i
,
r
i
]
[l_i,r_i]
[li,ri]会对哪些区间产生贡献,进行区间加减操作。
具体来说,第二个窗口接近
[
l
i
,
r
i
]
[l_i,r_i]
[li,ri]时,会产生附加贡献,离开
[
l
i
,
r
i
]
[l_i,r_i]
[li,ri]时,会减少附加贡献,这些变化在差分数组中的变化体现为某些位置的加减,接近时一阶差分数组
[
l
i
+
w
,
min
(
l
i
+
k
−
1
,
r
i
)
]
[l_i+w,\min(l_i+k-1,r_i)]
[li+w,min(li+k−1,ri)]每个数加一,离开时
[
max
(
l
i
+
k
,
r
i
+
1
)
,
r
i
+
k
−
w
]
[\max(l_i+k,r_i+1),r_i+k-w]
[max(li+k,ri+1),ri+k−w]减一,具体见代码。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
const int INF = 0x3f3f3f3f, N = 2005;
int n, m, k, ans;
int l[N], r[N], diff[N<<1];
int main()
{
scanf("%d%d%d", &n, &m, &k);
for (int i = 1; i <= m; ++i) scanf("%d%d", &l[i], &r[i]);
for (int i = k; i <= n; ++i) {
memset(diff, 0, sizeof(diff));
int sum = 0;
for (int j = 1; j <= m; ++j) {
int w = max(min(r[j], i) - max(l[j] - 1, i - k), 0);
sum += w;
if (l[j] - 1 + w <= r[j]) {
diff[l[j]+w-1]++;
diff[l[j]+k-1]--;
diff[r[j]]--;
diff[r[j]+k-w]++;
}
}
for (int j = 1; j < n; ++j) diff[j] += diff[j-1];
for (int j = 0; j < n; ++j) ans = max(ans, sum+=diff[j]);
}
printf("%d\n", ans);
return 0;
}