很明显我们要令到拥抱数最大,我们尽可能让假期在月尾开始且在月尾结束,天数不够我们尽可能让假期在月尾结束(代码好写),这个贪心是正确的是因为我们让假期在月尾结束,往前x天,也能保证假期尽量晚的开始,所以能保证取到的天数最大。所以大体思路是枚举我们在哪一个月结束,二分找我们要从哪里开始休假,然后取最大值就好了,具体实现看代码。
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<stack>
#include<utility>
#define int long long
using namespace std;
int n,x;
int d[500000],sum1[500000],sum2[500000],ans=-1;
signed main()
{
cin>>n>>x;
for(int i=1;i<=n;i++)
{
scanf("%lld",&d[i]);
d[i+n]=d[i];
}
int n2=n*2;
for(int i=1;i<=n2;i++)//这是个前缀和,方便处理数据
{
sum1[i]=sum1[i-1]+d[i];//这是月份天数的前缀和
sum2[i]=sum2[i-1]+((1+d[i])*d[i]/2);//这个是可以获取到的拥抱的前缀和
}
for(int i=n+1;i<=n2;i++)//找开始的月份
{
int l=1,r=i;
while(l<r)
{
int mid=l+r>>1;
if(sum1[i]-sum1[mid]<x)
{
r=mid;
}
else
{
l=mid+1;
}
}
int k=sum1[i]-sum1[l-1]-x;
ans=max(ans,sum2[i]-sum2[l-1]-((1+k)*k/2));//如果x天不足以支撑用完一个月份,我们就把开始天数减掉,这个可以保证我们尽量晚的开始
}
cout<<ans;
}