这题的区间因为有重叠,先考虑把重叠无用的区间去掉,考虑怎么去掉。
如图,红色那种区间是完全没有用的,按区间左端点从小到大排序之后,如果一个区间的右端点,比上一个有效区间的右端点还要小的话,那么就是无用的了,应该要删掉这个区间。这个操作用set来实现很方便。
然后考虑签到次数,这个条件怎么用,考虑到区间的价值都是正的,满足递增性,那么可以用尺取的方法来实现。如果签到次数有剩余,那么就尽量往右包括多点区间,直到签到次数不够用了,左边就收缩,舍弃区间,归还签到次数。这样重复是可以找到一段连续的最大值的。
注意一下区间的计算方法,这个多造几组数据可以看出端倪
#include<bits/stdc++.h>
#define max(a,b) a>b?a:b
using namespace std;
const int MAXN = 100000+10;
set<pair<int,int> > rset;//用pair来存区间
int n,m;
int main()
{
if (fopen("in.txt", "r") != NULL)
{
freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
}
while(cin>>n>>m)
{
rset.clear();
for(int i=0;i<n;i++)
{
int l,r;
scanf("%d%d",&l,&r);
rset.insert({l,r});
}
set<pair<int,int> >::iterator itp = rset.begin(),it=rset.begin();
it++;
while(it!=rset.end())
{
if(it->second<itp->second)
{
set<pair<int,int> >::iterator tmp = it;
it++;//指针先右移,不然删掉就不能右移了
rset.erase(tmp);//把这个无效区间删掉
}
else
{
it++;
itp++;
}
}
itp=rset.begin(),it=itp;
int ans=0;
int sum=itp->second - itp->first +1;
ans=sum+m;
int cost=0;
while(1)//尺取
{
while(cost>m)//左缩
{
set<pair<int,int> >::iterator tmp = itp;
itp++;
cost-=max(0,itp->first-tmp->second-1);
sum-=itp->first-tmp->first;
}
ans=max(ans,sum+m-cost);//更新最大值的时候把签到次数给用完
set<pair<int,int> >::iterator tmp = it;
it++;
if(it==rset.end()) break;
//右扩
sum+=it->second-tmp->second;
cost+=max(0,it->first-tmp->second-1);
}
if(cost<=m)
ans=max(ans,sum+m-cost);
printf("%d\n",ans);
}
return 0;
}