- 题目链接:https://codeforces.com/problemset/problem/1399/F
- 解题思路: 首先肯定是需要离散化线段。离散完了之后我们考虑区间dp, 定 义 d p [ i ] [ j ] : [ i , j ] 这 段 区 间 内 最 多 的 合 法 线 段 数 量 。 定义dp[i][j]:[i,j]这段区间内最多的合法线段数量。 定义dp[i][j]:[i,j]这段区间内最多的合法线段数量。那么显然有转移方程
- d p [ i ] [ j ] = m a x ( d p [ i ] [ j − 1 ] , d p [ i + 1 ] [ j ] ) dp[i][j] = max(dp[i][j-1], dp[i+1][j]) dp[i][j]=max(dp[i][j−1],dp[i+1][j])
-
d
p
[
i
]
[
j
]
=
m
a
x
(
d
p
[
i
]
[
j
]
,
d
p
[
i
]
[
k
]
+
d
p
[
k
+
1
]
[
j
]
)
dp[i][j] = max(dp[i][j], dp[i][k]+dp[k+1][j])
dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j])
每次转移完之后只需要加上以 i i i开头 j j j的线段数量就好了
const int N = 5e5 + 5;
int T, n;
struct node {
int x, y;
}p[N];
int a[N];
int dp[6005][6005];
vector <int> ve[N];
int main(void)
{
CLOSE;
cin >> T;
while (T --)
{
cin >> n;
for (int i = 1 ; i <= n ; i ++)
{
cin >> p[i].x >> p[i].y;
a[i*2-1] = p[i].x, a[i*2] = p[i].y;
}
sort (a + 1, a + 1 + 2 * n);
int len = unique (a + 1, a + 1 + 2 * n) - a - 1;
for (int i = 1 ; i <= n ; i ++)
{
p[i].x = lower_bound(a + 1, a + 1 + len , p[i].x) - a;
p[i].y = lower_bound(a + 1, a + 1 + len , p[i].y) - a;
ve[p[i].x].pb(p[i].y);
}
for (int i = 1 ; i <= len ; i ++)
for (int j = 1 ; j <= len ; j ++)
dp[i][j] = 0;
for (int l = 1 ; l <= len ; l ++)
{
for (int i = 1 ; i <= len ; i ++)
{
int j = i + l - 1;
if (j > len) break;
dp[i][j] = max (dp[i+1][j] , dp[i][j-1]);
int cnt = 0;
for (auto v : ve[i])
{
if (v == j) cnt ++;
if (v >= j) continue;
dp[i][j] = max (dp[i][j], dp[i][v] + dp[v+1][j]);
}
dp[i][j] += cnt;
}
}
cout << dp[1][len] << endl;
for (int i = 1 ; i <= len ; i ++)
ve[i].clear();
}
}