2017"百度之星"程序设计大赛 - 初赛(B)1006 小小粉丝度度熊

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

如图,红色那种区间是完全没有用的,按区间左端点从小到大排序之后,如果一个区间的右端点,比上一个有效区间的右端点还要小的话,那么就是无用的了,应该要删掉这个区间。这个操作用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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值