2017"百度之星"程序设计大赛

来源:互联网 发布:usb打印机端口不打印 编辑:程序博客网 时间:2024/06/06 21:42

这题的区间因为有重叠,先考虑把重叠无用的区间去掉,考虑怎么去掉。

如图,红色那种区间是完全没有用的,按区间左端点从小到大排序之后,如果一个区间的右端点,比上一个有效区间的右端点还要小的话,那么就是无用的了,应该要删掉这个区间。这个操作用set来实现很方便。

然后考虑签到次数,这个条件怎么用,考虑到区间的价值都是正的,满足递增性,那么可以用尺取的方法来实现。如果签到次数有剩余,那么就尽量往右包括多点区间,直到签到次数不够用了,左边就收缩,舍弃区间,归还签到次数。这样重复是可以找到一段连续的最大值的。




注意一下区间的计算方法,这个多造几组数据可以看出端倪

#include<bits/stdc++.h>#define max(a,b) a>b?a:busing 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;}


原创粉丝点击