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;
}