标签:
dp[ i ]表示到第i个位置最少要分多少下, dp[ i ] = min ( dp [ i ] , dp [ j ] + 1 ) j 在合适的范围内 ( 满足长度和最值差 )
对整个数组建立线段树维护最大值和最小值这样就可在nlogn的时间里求出某一段的最值差,这个范围是满足单调性的,所以对于每个i可以二分出j的最小值 .
对每个dp[i]建立线段树,可以在nlogn时间内求出最小的j.
所以总时间复杂度n^2logn
/* ***********************************************
Author :CKboss
Created Time :2015年03月11日 星期三 23时20分17秒
File Name :CF487B.cpp
************************************************ */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <queue>
#include <set>
#include <map>
using namespace std;
const int maxn = 100100;
const int INF = 1e6;
int n,l,s;
int a[maxn];
int maxnum[maxn<<2],minnum[maxn<<2];
/// seg tree
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef pair<int,int> pII;
void push_up(int rt)
{
maxnum[rt]=max(maxnum[rt<<1],maxnum[rt<<1|1]);
minnum[rt]=min(minnum[rt<<1],minnum[rt<<1|1]);
}
void build(int l,int r,int rt)
{
if(l==r)
{
minnum[rt]=maxnum[rt]=a[l];
return ;
}
int m=(l+r)/2;
build(lson); build(rson);
push_up(rt);
}
pII query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
return make_pair(maxnum[rt],minnum[rt]);
}
int m=(l+r)/2;
if(R<=m) return query(L,R,lson);
else if(L>m) return query(L,R,rson);
else
{
pII leftp=query(L,R,lson);
pII rightp=query(L,R,rson);
return make_pair( max( leftp.first,rightp.first)
, min( leftp.second, rightp.second ) );
}
}
int dp[maxn];
/// seg tree 2
int tree2[maxn<<2];
void push_up2(int rt)
{
tree2[rt]=min(tree2[rt<<1],tree2[rt<<1|1]);
}
void build2()
{
memset(tree2,63,sizeof(tree2));
}
void insert2(int val,int pos,int l,int r,int rt)
{
if(pos==l&&pos==r)
{
tree2[rt]=val;
return ;
}
int m=(l+r)/2;
if(pos<=m) insert2(val,pos,lson);
else insert2(val,pos,rson);
push_up2(rt);
}
int query2(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
return tree2[rt];
}
int m=(l+r)/2;
if(R<=m) return query2(L,R,lson);
else if(L>m) return query2(L,R,rson);
else
{
int one = query2(L,R,lson);
int two = query2(L,R,rson);
return min(one,two);
}
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
scanf("%d%d%d",&n,&s,&l);
for(int i=1;i<=n;i++)
{
dp[i]=INF;
scanf("%d",a+i);
}
build(1,n,1);
dp[0]=0; dp[1]=1;
if(l>1) dp[1]=INF;
build2();
insert2(0,0,0,n,1);
insert2(1,1,0,n,1);
for(int i=2;i<=n;i++)
{
/// binary search to find left bound
int low=1,high=i-l+1,leftb=-1;
while(low<=high)
{
int mid=(low+high)/2;
pII temp = query(mid,i,1,n,1);
if(temp.first-temp.second<=s)
{
leftb=mid; high=mid-1;
}
else low=mid+1;
}
if(leftb==-1) dp[i]=INF;
else
{
int mmm = query2(leftb-1,i-l,0,n,1);
dp[i]=mmm+1;
}
insert2(dp[i],i,0,n,1);
}
if(dp[n]>=INF) dp[n]=-1;
printf("%d\n",dp[n]);
return 0;
}
Codeforces 487B. Strip DP+线段树+二分
标签:
原文地址:http://blog.csdn.net/ck_boss/article/details/44220295