D. The Best Vacation(尺取&贪心)

思路:贪心,显然包含总天数越多的月越好。因此我们考虑从后往前取,因为是连续的 x x x天,所以直接不断让区间左端点减就可以,然后枚举所有的右端点。类似尺取的思想。其实也可以用前缀和+二分进行查找左端点。

p s : x ps:x ps:x也要用 l o n g   l o n g long\ long long long坑死我了。
传送门

AC代码:贪心做法

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
#define mst(a) memset(a,0,sizeof a)
ll a[N*2],ans;
int main(){
	ll n,x;
	scanf("%lld%lld",&n,&x); 
	for(ll i=1;i<=n;i++) scanf("%lld",&a[i]),a[i+n]=a[i];
	ll ans=0,sum=0,now=0,r=2*n-1; 
	for(ll i=2*n-1;i>=n;i--){
		  while(sum<x){
		  	  now+=a[r]*(a[r]+1)/2;
		  	  sum+=a[r--];
		  }
		  ans=max(ans,now-(sum-x)*(sum-x+1)/2);
		  sum-=a[i];
		  now-=a[i]*(a[i]+1)/2;
	}
	printf("%lld\n",ans);
	return 0;
} 

AC代码:前缀和+二分做法

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=4e5+5;
#define mst(a) memset(a,0,sizeof a)
ll a[N*2+100],pre[N*2+100],sum[N*2+100];
int main(){
	int n;
	ll x;
	scanf("%d%lld",&n,&x); 
	for(int i=1;i<=n;i++) scanf("%lld",&a[i]),a[n+i]=a[i],sum[n+i]=sum[i]=a[i]*(a[i]+1)/2;
	for(int i=1;i<=2*n;i++) pre[i]=pre[i-1]+a[i],sum[i]+=sum[i-1];
	ll ans=0;
	for(int i=n;i<=2*n;i++){
		 int l=0,r=i,left=-1;
		 while(l<r){
		 	 int mid=(l+r)/2;
		 	 if(pre[mid]<pre[i]-x) l=mid+1,left=mid;
		 	 else r=mid;
		 }
		 ll res=pre[i]-pre[left]-x;
		 ans=max(ans,sum[i]-sum[left]-res*(res+1)/2);
		}
	printf("%lld\n",ans);
	return 0;
}