2359. 读书计划
题目描述
Smart很喜欢读书,为了安排自己的读书计划,他会预先把要读的内容做好标记, A B表示一个页段,即第A到B面,当然A<B,若有两个页段A-B,B-C,则可以直接记为A-C,这样,他就可以一次看完,现在告诉你n个页段,请你帮他求出最长的一条页段,并输出这条页段的长度和组成它的页段个数。举个例子:
有 6 个页段:
2-7 1-3 3-12 12-20 7-10 4-50
那么连续的页段就有:
1-3,3-12,12-20长度为20-1+1=20由3个页段组成;
2-7,7-10长度为10-2+1=9由2个页段组成;
4-50长度为50-4+1=47由1个页段组成;
那么最长的一条就是第三个,所以结果为47 1。
需要注意的是:如果有两条不一样的连续的页段长度同时为最大,那么取组成页段数多的一条。
例子: 1-5,5-10,1-10
输出: 10 2
输入
第一行为一个整数n;
第2行到第n+1行,每行两个整数A B,记录一个页段的信息。
输出
输出一个整数,即最长的页段的长度和组成它的页段数。
样例输入
7
1 5
10 12
3 10
2 7
2 10
12 16
7 9
样例输出
15 3
【样例说明】
1-5长度为5由1个页段组成;
3-10,10-12,12-16长度为14由3个页段组成;
2-7,7-9长度为8由2个页段组成;
2-10,10-12,12-16长度为15由3个页段组成;
所以输出最长的页段的长度即15由3个页段组成。
数据范围限制
30%的数据:n≤20,0≤A<B≤500;
100%的数据:n≤500,0≤A<B≤500。
为了保证有序,我们定义一个结构体:
struct node
{
int st,ed,len;
} a[N];
st表示页段的开始页数;
ed表示页段的结束页数;
len表示开始页数到结束页数有多少页。
我们先按照开始页数将结构体进行排序,保证有序!
然后按照类似LIS的做法进行:
列出动态转移方程为:
f[i]表示以i为结束页的最长的页段的长度
由于题目要求还要组成它的页段数,所以我们还要用一个
数组b[i]来记录,表示以第 i个页段为结尾能阅读的最长页码所需的页段个数
我们分两种情况来讨论:
- b[i]=b[j]+1(f[i]<f[j]+a[i].len)
- b[i]=max(b[i],b[j]+1) (f[i]==f[j]+a[i].len)
code:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=510;
struct node
{
int st,ed,len;
} a[N];
int f[N],b[N];
bool cmp(node x,node y)
{
return x.st<y.st;
}
int main()
{
freopen("book.in","r",stdin);
freopen("book.out","w",stdout);
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i].st>>a[i].ed;
a[i].len=a[i].ed-a[i].st;
}
sort(a+1,a+1+n,cmp);
int maxn=0,maxd=0;
for(int i=1;i<=n;i++)
{
f[i]=a[i].len;
b[i]=1;
for(int j=1;j<i;j++)
{
if(a[j].ed==a[i].st&&f[j]+a[i].len>f[i])
{f[i]=f[j]+a[i].len;b[i]=b[j]+1;}
if(a[j].ed==a[i].st&&f[j]+a[i].len==f[i])
b[i]=max(b[i],b[j]+1);
}
maxn=max(maxn,f[i]);
if(maxn==f[i]) maxd=max(maxd,b[i]);
}
cout<<maxn+1<<' '<<maxd<<endl;
return 0;
}