线段树——讲课用——优化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);
}
用线段树维护区间最小值,就可以直接查询[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); }