【区间交集的处理手法】P5464
P5464
推一推发现是一棵二叉树。
然后没啥用。
考虑处理区间的话,按端点排序会比较清晰地得出关系。按左端点排序。
\(f(l,r)\) 表示最右,次右端点分别为 \(R_r,R_l\) 地方案数。
对于区间 \(i\),显然要有 \(R_l\lt L_i\le R_r\),然后分类转移一下。\(\mathcal O(n^3)\)。
cmd 题解里的一中高明枚举方法是,把第一维改成坐标而不是区间编号。
这样一遍加入 \(i\) 一边做前缀和,然后就可以完美地实现 \(\mathcal O(n^2)\) 地转移。比 BIT 暴力优化优雅很多。
#include <bits/stdc++.h>
#define pb emplace_back
#define fir first
#define sec second
using pii = std::pair<int, int>;
const int maxn = 2005;
const int mod = 1e9 + 7;
void add(int& x, int y) { if((x += y) >= mod) x -= mod; return ; }
void sub(int& x, int y) { if((x += y) >= mod) x -= mod; return ; }
int n, p, s[maxn << 1][maxn], ans;
pii a[maxn];
int main() {
scanf("%d", &n);
for(int i = 1;i <= n;++ i)
scanf("%d %d", &a[i].fir, &a[i].sec);
std::sort(a + 1, a + 1 + n);
p = 1;
for(int i = 1;i <= n;++ i) {
while(p < a[i].fir) {
for(int r = 1;r < i;++ r)
add(s[p][r], s[p - 1][r]);
++ p;
}
for(int r = 1;r < i;++ r)
if(a[i].fir <= a[r].sec) {
if(a[r].sec >= a[i].sec)
add(s[a[i].sec][r], s[a[i].fir - 1][r]);
else
add(s[a[r].sec][i], s[a[i].fir - 1][r]);
}
++ s[0][i];
for(int j = 1;j < p;++ j)
add(s[j][i], s[j - 1][i]);
}
for(int i = p - 1;i <= 4000;++ i)
for(int j = 1;j <= n;++ j)
add(ans, s[i][j]);
printf("%d\n", ans);
return 0;
}

珂朵莉珂爱!
浙公网安备 33010602011771号