• 金题大战Vol.0 B、序列


    金题大战Vol.0 B、序列

    题目描述

    给定两个长度为 (n) 的序列(a), (b)

    你需要选择一个区间([l,r]),使得(a_l+…+a_r>=0)(b_l+…+b_r>=0)。最大化你选择的区间长度。

    输入格式

    第一行一个整数(n),第二行(n)个整数(a_1-a_n),第三行n个整数(b_1-b_n)

    输出格式

    一行一个整数表示(max(r-l+1))。保证至少有一个区间满足条件。

    样例

    样例输入

    5
    2 -4 1 2 -2
    -2 3 1 -3 1

    样例输出

    1

    数据范围与提示

    对于(20\%) 的数据,(n<=5000)

    对于(60\%) 的数据,(n<=10^5)

    对于(100\%) 的数据,(1<=n<=10^6,|ai|, |bi|<=10^9)。 数据有一定梯度。

    分析

    乍看上去这一道题似乎不太好处理,要同时满足下标、(a)(b)三个条件

    突破点就在于怎么把限制条件一维一维地删去

    首先我们把题目中给出的数组转化成前缀和的形式

    (suma[r]>=suma[l],sumb[r]>=sumb[l])

    我们将 (suma) 从小到大排一下序

    这样我们每一次从左到右遍历,就相当于消去了一维

    我们只考虑 (sumb) 和坐标的关系即可

    这种关系我们可以用树状数组去维护,即把 (sumb) 的值作为树状数组的下标,把原先的编号作为树状数组的权值

    这样在每次遇到一个点时,我们在树状数组中查询 (sumb) 比它小的最小的下标

    同时更新下标为 (sumb) 的节点的值为当前点的编号

    (sumb) 比较大,并且有负数,因此考虑离散化

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e6+5;
    typedef long long ll;
    inline int read(){
    	int x=0,f=1;
    	char ch=getchar();
    	while(ch<'0' || ch>'9'){
    		if(ch=='-') f=-1;
    		ch=getchar();
    	}
    	while(ch>='0' && ch<='9'){
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return x*f;
    }
    int a[maxn],b[maxn],n,cnt,tr[maxn];
    ll suma[maxn],sumb[maxn];
    struct asd{
    	int wz;
    	ll jla,jlb;
    }jl[maxn];
    bool cmp(asd aa,asd bb){
    	return aa.jla<bb.jla;
    }
    int lb(int xx){
    	return xx&-xx;
    }
    void ad(int wz,int val){
    	for(int i=wz;i<=n;i+=lb(i)){
    		tr[i]=min(tr[i],val);
    	}
    }
    int cx(int wz){
    	int ans=0x3f3f3f3f;
    	for(int i=wz;i>0;i-=lb(i)){
    		ans=min(ans,tr[i]);
    	}
    	return ans;
    }
    int main(){
    	freopen("B.in","r",stdin);
    	freopen("B.out","w",stdout);
    	int ans=1,bef,wz;
    	memset(tr,0x3f,sizeof(tr));
    	n=read();
    	for(register int i=1;i<=n;i++){
    		a[i]=read();
    		suma[i]=suma[i-1]+(ll)a[i];
    	}
    	for(register int i=1;i<=n;i++){
    		b[i]=read();
    		sumb[i]=sumb[i-1]+(ll)b[i];
    	}
    	for(register int i=1;i<=n;i++){
    		jl[i].jla=suma[i];
    		jl[i].jlb=sumb[i];
    		if(jl[i].jla>=0 && jl[i].jlb>=0){
    			ans=max(ans,i);
    		}
    		jl[i].wz=i;
    	}
    	sort(jl+1,jl+1+n,cmp);
    	sort(sumb+1,sumb+1+n);
    	cnt=unique(sumb+1,sumb+1+n)-sumb-1;
    	for(int i=1;i<=n;i++){
    		wz=lower_bound(sumb+1,sumb+cnt+1,jl[i].jlb)-sumb;
    		bef=cx(wz);
    		if(bef>=jl[i].wz){
    			ad(wz,jl[i].wz);
    			continue;
    		}
    		ans=max(ans,jl[i].wz-bef);
    		ad(wz,jl[i].wz);
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
    
  • 相关阅读:
    MySQL实现对身份证格式验证
    基于Flink1.11的SQL构建实时数仓探索实践
    详解flink 1.11 中的CDC (Change Data Capture)
    ERROR 1093 (HY000): You can't specify target table 'xxx' for update in FROM clause 问题解决
    用Flink SQL CDC + ES实现数据实时化真香
    程序员创业及如何提高影响力
    Hive高阶函数posexplode(可以用于生成动态日期序列)
    Hive使用ORC格式存储进行优化
    数据仓库逻辑区域及各区域的功能和特点
    hive错误排查一:hive中执行 drop table命令卡住,删除表不成功
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/13504284.html
Copyright © 2020-2023  润新知