首页 技术 正文
技术 2022年11月6日
0 收藏 972 点赞 870 浏览 1714 个字

首先注意一下题面要求,使得选出的线段两两要么包含要么不相交,也就是说一条线段可能会出现不相交的几条线段,而这些线段上面也可能继续这样包含线段。然后我们可以发现我们要做的实际上是在这条线段上选取几条线段然后递归求出子问题,这是一个 \(dp\) 的形式,令 \(f_i\) 表示在线段 \(i\) 上最多能选出多少个满足条件的区间。但是在这里拓扑序我们还未知,我们看看能否求出这个 \(dp\) 的拓扑序。我们发现对于任意一条线段我们能选择被它包含的线段必然左端点大于该线段左端点,右端点大于该线段左端点,那么我们只需要按照右端点排序,那么每次能转移到的区间就都会已经计算完毕。但需要注意的是如果右端点相同,我们还要按照左端点从大到小排序,这样才能保证小的线段先算。

接下来考虑如何转移,实际上这里需要求解的一个问题就是每个线段有一个权值,选出一些不相交的线段使得它们的权值最大。接下来可以发现如果当前线段能选,那么上次选的最右边线段的右端点一定要比当前线段的左端点要靠前,于是可以令 \(dp_i\) 表示当前选择的最右边的右端点在 \(i\) 的最大权值,有转移:

\[dp_{a_i.r} = \max\{dp_{a_j.r} + f_i\}(a_j.r < a_i.l)
\]

将 \(f_i\) 拉出来这就是一个前缀 \(\max\) 的形式,因为右端点是单调递增的,因此只需要沿途维护一个指针扫过来并统计即可。本题当中值域很大?可以发现我们只关注大小关系,离散化即可。

#include<bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for(int i = l; i <= r; ++i)
const int N = 6000 + 5;
struct node{
int l, r;
}a[N];
int T, n, tot, cnt, f[N], g[N], d[N], dp[N];
int read(){
char c; int x = 0, f = 1;
c = getchar();
while(c > '9' || c < '0'){ if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
bool cmp(node a, node b){
return a.r == b.r ? a.l > b.l : a.r < b.r;
}
int main(){
T = read();
while(T--){
n = read(), tot = 0;
rep(i, 1, n) a[i].l = read(), a[i].r = read(), d[++tot] = a[i].l, d[++tot] = a[i].r;
sort(d + 1, d + tot + 1), sort(a + 1, a + n + 1, cmp);
cnt = unique(d + 1, d + tot + 1) - d - 1;
rep(i, 1, n){
a[i].l = lower_bound(d + 1, d + cnt + 1, a[i].l) - d;
a[i].r = lower_bound(d + 1, d + cnt + 1, a[i].r) - d;
}
rep(i, 1, n){
int P = 0, l = 0;
rep(j, 1, a[i - 1].r) dp[j] = g[j] = 0;
rep(j, 1, i - 1) if(a[j].l >= a[i].l){
if(a[j].r != l) ++P;
while(P < a[j].r) g[P] = g[P - 1], ++P;
dp[a[j].r] = max(dp[a[j].r], g[a[j].l - 1] + f[j]), g[P] = max(g[P - 1], dp[a[j].r]);
l = a[j].r;
}
f[i] = g[P] + 1;
}
int P = 0, l = 0;
rep(i, 1, a[n].r) dp[i] = g[i] = 0;
rep(i, 1, n){
if(a[i].r != l) ++P;
while(P < a[i].r) g[P] = g[P - 1], ++P;
dp[a[i].r] = max(dp[a[i].r], g[a[i].l - 1] + f[i]), g[P] = max(g[P - 1], dp[a[i].r]);
l = a[i].r;
}
printf("%d\n", g[a[n].r]);
rep(i, 1, a[n].r) dp[i] = f[i] = g[i] = 0;
}
return 0;
}
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,484
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,899
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,732
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,485
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:8,125
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:5,285