【题目翻译】
给你n个月,每个月天数有d[i]天你需要选取连续的几天(可以跨月、跨年)
然后你得到的收益为这些天是在所在月份的第几天对应的数字的和。
比如你选了第2月(设有30天)的第29、30天以及3月的第1,2天。
那么你的收益就是29+30+1+2
然后现在的问题是,让你从n个月份当中选出来连续的x天,要求他们的收益总和最大。
【题解】
首先需要明确一点,你选出来的这x天,最后一天肯定是某个月的最后一天。不然总能有更优的方案。
证明如下:
明白这一点之后就好做了。
弄一个前i个月天数的前缀和pday[i]用来查前x天所在的月份。
再弄一个前i个月(1+...+d[1]+1+...+d[2]+1+...+d[i])的每个月天数和的前缀和。用来查前x天的收益和。
枚举最后一段在哪一个月,二分出来前x天所在月份,计算出相应代价就好。
二分的时候注意边界,然后跨年的情况,你就直接把d[]再复制一遍到后面就行。
【代码】
#include<bits/stdc++.h>
#define ll long long
#define rei(x) scanf("%d",&x)
#define rel(x) scanf("%I64d",&x)
#define rep1(i,a,b) for (int i = a;i <= b;i++)
#define rep2(i,a,b) for (int i = a;i >= b;i--)
using namespace std;
const int N = 4e5;
int n;
ll x,d[N+10],pday[N+10],ptot[N+10];
int main(){
//cout<<(1LL<<62)<<endl;
#ifdef LOCAL_DEFINE
freopen("D:\rush.txt","r",stdin);
#endif
int T;
rei(n);rel(x);
rep1(i,1,n) rel(d[i]);
rep1(i,n+1,2*n) d[i] = d[i-n];
n = n*2;
rep1(i,1,n){
//d[i]<=10^6
//pday[i]<=2*10^12
//4*10^5*10^12
//4*10^17
pday[i] = pday[i-1]+d[i];
ptot[i] = ptot[i-1]+(1+d[i])*d[i]/2;
}
ll ans = 0;
rep1(j,1,n){
int l = 0,r = j,temp = j;
//要找这样一个temp,p[j]-p[temp]<=x,p[j]-p[temp-1]>x
while (l<=r){
int mid = (l+r)/2;
if ((pday[j]-pday[mid])<x){
temp = mid;
r = mid-1;
}else l = mid + 1;
}
if (temp==0) continue;
ll tmp = pday[j]-pday[temp];
ll lastdays = x-tmp;
ll totval = ptot[j]-ptot[temp];
ll firstdays = d[temp]-lastdays;
if (firstdays<0) continue;
totval = (1+d[temp])*d[temp]/2 - (1+firstdays)*firstdays/2 + totval;
ans = max(ans,totval);
}
printf("%lld
",ans);
return 0;
}