思路
二分空题段长度,然后dp,用线段树维护
code
#include<bits/stdc++.h> #define inf 1000000007 using namespace std; int n,m,ans,a[50005],f[50005],tr[3000005]; long long find(int l,int r,int k,int x,int y) { if(x>y)return 0; if(l==x&&r==y) { return tr[k]; } int mid=(l+r)/2; if(y<=mid)return find(l,mid,k*2,x,y); if(x>mid)return find(mid+1,r,k*2+1,x,y); return min(find(l,mid,k*2,x,mid),find(mid+1,r,k*2+1,mid+1,y)); } void build(int l,int r,int k) { tr[k]=10000000000000000; if(l==r)return; int mid=(l+r)/2; build(l,mid,k*2); build(mid+1,r,k*2+1); } void fix(int l,int r,int k,int x) { if(l==r) { tr[k]=f[x]; } else { int mid=(l+r)/2; if(x<=mid)fix(l,mid,k*2,x); else fix(mid+1,r,k*2+1,x); tr[k]=min(tr[k*2],tr[k*2+1]); } } bool dp(int s) { build(1,n,1); for(int i=1;i<=n;i++) { int sum; if(i-s-1<=0||i==1)sum=0; else sum=find(1,n,1,i-s-1,i-1); f[i]=sum+a[i]; fix(1,n,1,i); } for(int j=n;j>=n-s;j--) { if(f[j]<=m)return 1; }return 0; } int main () { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%d",&a[i]); int l=1,r=n; while(l<=r) { int mid=(l+r)/2; if(dp(mid)) { ans=mid; r=mid-1; } else { l=mid+1; } } printf("%d ",ans); return 0; }