Codeforces 1358 D. The Best Vacation(二分)

题目链接
题目大意:
一年中有n个月,每个月有mi天,每个月中的第i天所获得的积分为i分,要在其中找出连续的x天,使其积分和最大,这x天可以不属于同一年,问积分最多是多少?

解题思路:
首先可以知道选择的最大的那个区间一定以某个月的最后一天为终点。
证明(反证):
假设选择的最优区间为[L,R],其中R不是某个月的终点,就说明R的右边为R+1,其中L,R表示区间最左边和最右边所能获得的积分。

  1. L=R,此时区间右移一位,ans+(R+1)-L,所以ans增加,不是最优区间。
  2. L<R,此时区间右移一位,ans+(R+1)-L>ans+1,所以ans增加,不是最优区间。
  3. L>R。
    如果L=R+1,不妨对区间一直进行右移,因为ans一直不变,直到L或R到达所在月的最后一天。如果是R先到达最后一天或者同时到达,此时积分和和假设的区间一样,可以把R是最后一天的区间当做假设区间,则此时与假设相矛盾。如果是L先到达最后一天,则再右移一次ans+(x+1)-y=ans,如果R也到达最后一天,则同样与假设矛盾,如果R没有到达最后一天,则再次右移为ans-1+R+1 > > > ans,则ans增加不是最优区间。
    如果L>R+1,则对区间左移一位,ans+(L-1)-R>ans,不是最优区间。

已经知道终点必须是某个月的最后一天,所以只需要枚举每个月的最后一天作为R,然后二分寻找L所在的月份,结果就是把中间月份全都加起来,L所在月份取部分就可以了,用前缀和处理一下。

解题代码:

#include<bits/stdc++.h>
using namespace std;
mt19937 rng_32(chrono::steady_clock::now().time_since_epoch().count());
typedef long long ll;
const int maxn=(2e5+10)*2;
ll a[maxn];
ll pre[maxn],pre_sum[maxn];
//计算1+2+...+mx 的后u项的和
ll cal(ll mx,ll u)
{
    ll ret=mx*(mx+1ll)/2ll;
    ll sub=mx-u;
    ret-=(sub+1ll)*sub/2ll;
    return ret;
}
int main()
{
    ll n,x;
    cin>>n>>x;
    for (int i=n+1;i<=n+n;i++)
    {
        scanf("%lld",&a[i]);
        a[i-n]=a[i];
    }
    for(int i=1;i<=n+n;i++)
    {
        pre[i]=pre[i-1]+a[i];
        pre_sum[i]=pre_sum[i-1]+cal(a[i],a[i]);
    }
    ll ans=0;
    for (ll i=n+1;i<=n+n;i++)
    {
        ll l=1,r=i+1;
        while (l+1ll<r)
        {
            ll mid=(l+r)>>1ll;
            if (pre[i]-pre[mid-1]>=x)
            l=mid;
            else
            r=mid;
        }
        ll tmp=pre_sum[i]-pre_sum[l];
        ll sub=x-(pre[i]-pre[l]);
        tmp+=cal(a[l],sub);
        ans=max(ans,tmp);
    }
    cout<<ans<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值