题目链接:The Best Vacation
题意:
给你n个月份,每一个月份有di天。你可以呆在那里x天(x天要连续),如果你在某月的第y天呆在这。那么你的拥抱值就加y
1<=n<=2e5
1<=di<=1e6
题解:
首先这段日期的结尾一定是月末。下面证明
如果x<=max(d1,d2...dn)
那么肯定是在那个max(d1,d2...dn)那个月最后x天呆在那得到的拥抱值最大
如果选取的这段日期至少覆盖到两个月份。如果右端点不是月末的话,假设左端点对应的日期大于右端点对应的日期,那么整体往左移动区间就能使得答案增加;同理假设左端点对应的日期小于右端点对应的日期可以整体往右移动。最后都会使得右端点靠到某个月的月末。
代码:
#include<stdio.h> #include<algorithm> #include<iostream> #include<string> #include<queue> #include<deque> #include<string.h> #include<map> #include <iostream> #include <math.h> #define Mem(a,b) memset(a,b,sizeof(a)) const double II = acos(-1); const double PP = (II*1.0)/(180.00); using namespace std; typedef long long ll; const int INF=0x3f3f3f3f; const double eps=1e-6; const double PI=acos(-1); const int mod=998244353; const int maxn=2e5+10; long long d[400005]; long long sum[400005]; long long ssum[400005]; long long ans=0; long long n,x;//xһ��Ҫ��long long ��Ϊ��d�ĺ� int check(long long mid,long long k) { if(sum[k]-sum[mid]>=x) return 0; else { if(sum[k]-sum[mid-1]>=x) return 1; else return 2; } } int main() { cin>>n>>x; int i; for(i=1;i<=n;i++) { scanf("%lld",&d[i]); d[i+n]=d[i]; } for(i=1;i<=2*n;i++) { sum[i]=sum[i-1]+d[i]; ssum[i]=ssum[i-1]+(1+d[i])*d[i]/2; } for(i=n+1;i<=2*n;i++) { long long l=1,r=i,mid,pos; while(1) { mid=(l+r)/2; int judge=check(mid,i); if(judge==2) r=mid; else if(judge==0) l=mid+1; else { pos=mid; break; } } if(pos==i)//��ͬһ���� { ans=max(ans,x*d[i]-(long long)x*(x-1)/2*1); } else { long long temp=ssum[i]-ssum[pos]; long long xx=x-(sum[i]-sum[pos]); temp+=xx*d[pos]-xx*(xx-1)/2; ans=max(ans,temp); } } cout<<ans<<endl; return 0; }