您的位置:首页 > 其它

UVALive_6609_Minimal Subarray Length(RMQ+二分)

2014-11-18 19:50 459 查看
题型:数据结构

题意:在n个数中求出最短连续序列,是的序列之和大于等于X。

分析:

一开始想是单调队列,或者单纯的二分,但是由于数据有正有负,所以其前缀和sum数组并没有单调性,所以这个方法不行。

后来想到,对sum数组,要求有这样的解,sum[j] - sum[i] ≥ x

枚举起点i,然后二分区间[i+1,n],每次用l到mid之间的sum最大值减去sum[i]看是否≥ x。

如果成立,说明左区间存在答案,那么往左边二分;

如果不成立,就是说连左区间的最大值都不能满足答案,那么左区间根部不存在答案,那么就往右区间二分。

然后更新最短长度的答案。

复杂度O(nlog(n))

代码:

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL inf=0x3f3f3f3f3f3f3f3fLL;
const int M=5e5+10;
class Range_Maximum_Query{
int LOG[M];
LL dpmax[M][20],dpmin[M][20];
public:
void init(){
LOG[0]=-1;
for(int i=1;i<M;i++){
LOG[i]=LOG[i>>1]+1;
}
}
void Make_RMQ(int n,LL a[]){
for(int i=1;i<=n;i++){
dpmax[i][0]=dpmin[i][0]=a[i];
}
for(int j=1;j<=LOG
;j++){
for(int i=1;i+(1<<j)-1<=n;i++){
dpmax[i][j]=max(dpmax[i][j-1],dpmax[i+(1<<(j-1))][j-1]);
dpmin[i][j]=min(dpmin[i][j-1],dpmin[i+(1<<(j-1))][j-1]);
}
}
}
LL get_RMQ(int a,int b,bool big){
int k=LOG[b-a+1];
if(big)
return max(dpmax[a][k],dpmax[b-(1<<k)+1][k]);
return min(dpmin[a][k],dpmin[b-(1<<k)+1][k]);
}
}rmq;

LL a[M],sum[M];
int main(){
int t,n,m;
rmq.init();
while(~scanf("%d",&t)){
while(t--){
scanf("%d%d",&n,&m);
sum[0]=0;
for(int i=1,in;i<=n;i++){
scanf("%d",&in);
a[i]=in;
sum[i]=sum[i-1]+a[i];
}
rmq.Make_RMQ(n,sum);
int ans=0x3f3f3f3f;
for(int i=1;i<=n;i++){
int L=i,R=n;
while(L<=R){
int mid=(L+R)>>1;
LL big=rmq.get_RMQ(i,mid,1);
if(big-sum[i-1]>=m){
ans=min(ans,mid-i+1);
R=mid-1;
}
else{
L=mid+1;
}
}
}
if(ans==0x3f3f3f3f) ans=-1;
printf("%d\n",ans);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: