问题 E: MAX 的读书计划

时间限制: 1 Sec 内存限制: 128 MB
[提交] [状态]
题目描述
MAX 很喜欢读书,为了安排自己的读书计划,他会预先把要读的内容做好标记,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,n<500;
第二行到第n+1行,每行两个整数A,B,记录一个页段的信息。0<=A<B<500
输出
输出一个整数,即最长的页段的长度和组成它的页段数。
样例输入 Copy
7
1 5
10 12
3 10
2 7
2 10
12 16
7 9
样例输出 Copy
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

  • 思路:两个点如果不能直接连通的话需要在她直接找到一个点连通 这个点与第一个点,在联通这个点跟后一个点,所以我们就要在连接点上来看了。先设二维数组,存放长度,且存在。然后就是判断了,如果两点之间有连接点,则判断前一点是否可由他这之前的到达,如果能,判断长度与原本的大小,大则赋值 并标记下来连接点,不能到到直接比较他遇到当前的长度大小。
  • 然后找到最长。然后找桥梁最多的。

代码:

#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
using namespace std;
const int maxn=2e5+1010;
#define
const int mod=1e9+7;
const int MOD=10007;

inline int read() {
int x=0;
bool t=false;
char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}

priority_queue<ll , vector<ll> , greater<ll> > mn;//上 小根堆 小到大
priority_queue<ll , vector<ll> , less<ll> > mx;//下 大根堆 大到小
map<ll,ll>mp;

ll n,m,t,l,r,p;
ll sum,ans,res,cnt,flag
,maxx,minn;
bool isprime[maxn];
ll a[maxn],b[maxn],c[maxn];
ll dis[maxn],vis[maxn];
ll dp[1010][1010];
string str,s;

struct king {
ll id;
string str;
}q[maxn];
bool cmp(king a,king b){
if(a.id!=b.id) return a.id>b.id;
else return a.str<b.str;
}
ll qpow(ll a,ll b){
ll sum=1;
while(b){
if(b&1) sum=sum*a%mod;
b>>=1;
a=a*a%mod;
}
return sum;
}


int main(){
cin>>n;
for(int i=1;i<=n;i ++)
{
scanf("%lld%lld",&l,&r);
dp[l][r]=r-l+1;
maxx=max(maxx,r);
}
for(int i=0;i<=maxx;i++){
for(int j=0;j<i;j++){
if(dp[j][i]){//存在
if(dis[j]){
if(dis[i]<dis[j]+dp[j][i]){
dis[i]=dis[j]+dp[j][i]-1;//最大长度
vis[i]=j;//这个的中间连接点是j 也就是前一个点
}
}else {//这个连接点不存在 直接用 新的一个点做根
dis[i]=max(dis[i],dp[j][i]);
}
}
}
}
for(int i=0;i<=maxx;i++)
{
if(dis[i]>minn)
minn=dis[i];//找到最长的
}
sum=1;
for(int i=0;i<=maxx;i++){
if(dis[i]==minn){
l=1,r=i;
while(vis[r]!=0){//由最后一点 向前找
l++;
r=vis[r];
}
sum=max(sum,l);
}
}
cout<<minn<<" "<<sum<<endl;
return 0;
}