题目链接
http://codevs.cn/problem/3342/
思路
最大化最小值,二分最长空题段
令f[i]表示抄第i道题所花费的最小时间
f[i]=min(f[j])+time[i] max(0,i-mid-1)<=j<=i-1
直接暴力找[i-mid-1,i-1]内f[j]的最小值的话会超时,所以我们可以用线段树维护区间最小值
#include<bits/stdc++.h>
using namespace std;
const int maxx = 5e4+10;
const int inf = 0x3f3f3f3f;
int a[maxx];
int t[maxx<<2];
int n,m;
void build(int l,int r,int rt)
{
t[rt]=inf;
if(l==r)return;
int mid=(l+r)/2;
build(l,mid,rt*2);
build(mid+1,r,rt*2+1);
}
void update(int l,int r,int x,int c,int rt)
{
if(l==r)
{
t[rt]=c;
return;
}
int mid=(l+r)/2;
if(x<=mid)update(l,mid,x,c,rt*2);
else update(mid+1,r,x,c,rt*2+1);
t[rt]=min(t[rt*2],t[rt*2+1]);
}
int query(int l,int r,int p,int q,int rt)
{
if(p<=l&&r<=q)return t[rt];
int mid=(l+r)/2;
int res=inf;
if(p<=mid)res=min(res,query(l,mid,p,q,rt*2));
if(q>mid)res=min(res,query(mid+1,r,p,q,rt*2+1));
return res;
}
int check(int k)
{
build(0,n,1);
update(0,n,0,0,1);
for(int i=1;i<=n;i++)
{
int p=query(0,n,max(0,i-k-1),i-1,1);
update(0,n,i,p+a[i],1);
}
int res=query(0,n,n-k,n,1);
if(res<=m)return 1;
else return 0;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
int l=0,r=n;
while(l<=r)
{
int mid=(l+r)/2;
if(check(mid))r=mid-1;
else l=mid+1;
}
printf("%d
",r+1);
return 0;
}