线段树——讲课用——优化DP

题目链接:http://codevs.cn/problem/3342/

 

题解:

最小化最大值:二分

二分最长空题段

令f[i]表示抄第i道题所花费的最小时间

状态转移方程:f[i]=min(f[j])+time[i]    max(0,i-mid-1)<=j<=i-1

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 50001
using namespace std;
int n,t,l,r,mid,ans,f[N],a[N];
inline bool check(int k)
{
    memset(f,127,sizeof(f));
    f[0]=0;
    for(int i=1;i<=n;i++)
     for(int j=max(i-k-1,0);j<i;j++)
      f[i]=min(f[i],f[j]+a[i]);
    int tmp=0x7fffffff;
    for(int i=n-k;i<=n;i++) tmp=min(tmp,f[i]);
    if(tmp<=t) return true;
    return false;
}
int main()
{
    scanf("%d%d",&n,&t);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    l=0,r=n;
    while(l<=r)
    {
        mid=l+r>>1;
        if(check(mid)) {ans=mid;r=mid-1;}
        else l=mid+1;
    }
    printf("%d",ans);
}
View Code

用线段树维护区间最小值,就可以直接查询[i-mid-1,i-1]内的最小值

#include<cstdio>
#include<algorithm>
#define N 50001
#define INF 100000010
using namespace std;
int n,t,ql,qr,mid,ans,f[N],a[N];
struct node{int l,r,key;}tr[N*4];
inline int read()//读入优化 
{
    int x=0;char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
    return x;
}
inline void begin(int k,int l,int r)//初始化 
{
    tr[k].key=INF;
    if(l==r) return;
    int mid=l+r>>1;
    begin(k<<1,l,mid);
    begin((k<<1)+1,mid+1,r);
}
inline int query(int k,int opl,int opr)//区间查询 
{
    if(tr[k].l>=opl&&tr[k].r<=opr) return tr[k].key;
    int mid=tr[k].l+tr[k].r>>1;
    {
        int ll=INF;if(opl<=mid) ll=query(k<<1,opl,opr);
        int rr=INF;if(opr>mid) rr=query((k<<1)+1,opl,opr);
        return min(ll,rr);
    }    
}
inline void change(int k,int x,int y)//单点修改 
{
    if(tr[k].l==tr[k].r) {tr[k].key=min(tr[k].key,y);return;}
    int mid=tr[k].l+tr[k].r>>1;
    if(x<=mid) change(k<<1,x,y);
    else change((k<<1)+1,x,y);
    tr[k].key=min(tr[k<<1].key,tr[(k<<1)+1].key);
}
inline bool check(int k)
{
    begin(1,0,n);
    change(1,0,0);
    for(int i=1;i<=n;i++) 
    {
        int p=query(1,max(0,i-k-1),i-1);
        change(1,i,p+a[i]);
    }
    int tmp=0x7fffffff;
    if(query(1,n-k,n)<=t) return true;
    return false;
}
inline void build(int k,int l,int r)//建树 
{
    tr[k].l=l;tr[k].r=r;
    if(l==r) return;
    int mid=l+r>>1;
    build(k<<1,l,mid);
    build((k<<1)+1,mid+1,r);
}
int main()
{
    scanf("%d%d",&n,&t);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    build(1,0,n);
    ql=0,qr=n;
    while(ql<=qr)
    {
        mid=ql+qr>>1;
        if(check(mid)) {ans=mid;qr=mid-1;}
        else ql=mid+1;
    }
    printf("%d",ans);
}
View Code

 

posted @ 2019-07-07 10:00  TRTTG  阅读(284)  评论(0编辑  收藏  举报