codevs 3342 最大化最小值

题目链接

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\n",r+1);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/HooYing/p/11689336.html