zoukankan      html  css  js  c++  java
  • 序列

    题目描述

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

    你需要选择一个区间[l, r],使得al+…+ar>=0且bl+…+br>=0。最大化你选择的区间长度。

    输入格式

    第一行一个整数n,第二行n个整数a1~an,第三行n个整数b1~bn。

    输出格式

    一行一个整数表示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。 数据有一定梯度。

    简单解释

    理解题意,我们发现一个合法的区间要满足以下条件:

    [l leq r ]

    [sumA[l] leq sumA[r] ]

    [sumB[l] leq sumB[r] ]

    (sum) 为前缀和。然后玩意儿这一看就是个三维偏序,然后CDQ搞它就完了

    其实这题并不用CDQ分治,不要想太多...当然你非要用也不拦你。

    所以,先按 (sumA) 从小到大排一下序,这样我们在枚举的时候自然就满足了第二个条件。

    排完序,从1开始枚举,显然每个 (i) 会有一个对应的 (sumb),然后我们就需要在小于这个(sumb)(sumb)中找到一个最小的下标 (l),看这个 (l)(i) 是否满足 (l leq i),如果是,更新答案。

    以上操作显然要用数据结构来维护,所以上树状数组。(不要线段树,T飞)

    显然树是对(sumb)来开的,而(sumb)有点大,所以离散化一下。

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6 + 10;
    char buf[1 << 20], *p1 = buf, *p2 = buf;
    char getc() {
    	if(p1 == p2) {
    		p1 = buf, p2 = buf + fread(buf, 1, 1 << 20, stdin);
    		if(p1 == p2) return EOF; 
    	}
    	return *p1++;
    }
    int read() {
    	int s = 0, w = 1;
    	char c = getc();
    	while(c < '0' || c > '9') {if(c == '-') w = -1; c = getc();}
    	while(c >= '0' && c <= '9') s = s * 10 + c - '0', c = getc();
    	return s * w;
    }
    
    int n;
    
    struct NODE {
    	long long a, b;
    	int id;
    }Index[maxn];
    
    bool CMP(NODE x, NODE y) {return x.a < y.a;}
    
    int w[maxn << 2];
    
    void Change(int x, int val) {
    	for(; x <= n; x += (x & -x)) w[x] = min(w[x], val);
    }
    
    long long Ask(int x) {
    	int ans = INT_MAX;
    	for(; x; x -= (x & -x)) ans = (ans < w[x] ? ans : w[x]);
    	return ans;
    }
    
    long long sum1[maxn], sum2[maxn];
    
    int main() {
    	freopen("B.in", "r", stdin);
    	freopen("B.out", "w", stdout);
    	n = read();
    	for(int i = 1; i <= n; i++) {
    		sum1[i] = read() + sum1[i - 1];
    		Index[i].a = sum1[i];
    		Index[i].id = i;	
    	}
    	for(int i = 1; i <= n; i++) {
    		sum2[i] = read() + sum2[i - 1];
    		Index[i].b = sum2[i];
    	}
    	
    	long long ans = 1;
    	for(int i = 1; i <= n; i++) 
    		if(sum1[i] >= 0 && sum2[i] >= 0) ans = (ans > i ? ans : i);
    		
    	sort(Index + 1, Index + 1 + n, CMP);
    	sort(sum2 + 1, sum2 + 1 + n);
    	int len = unique(sum2 + 1, sum2 + 1 + n) - sum2 - 1;
    	
    	memset(w, 0x3f, sizeof w);
    	for(int i = 1; i <= n; i++) {
    		int p = lower_bound(sum2 + 1, sum2 + 1 + len, Index[i].b) - sum2;
    		Change(p, Index[i].id);
    		ans = max(ans, Index[i].id - Ask(p));
    	}
    	printf("%lld
    ", ans);
    	return 0;
    }
    
    
  • 相关阅读:
    [读书笔记]子查询
    [读书笔记]SQL约束
    [转载]NoSQL数据库的基础知识
    利用C#实现对excel的写操作
    [转载]SQL Server内核架构剖析
    利用花生壳和IIS发布网页过程
    [读书笔记]ASP.NET的URL路由引擎
    [翻译]比较ADO.NET中的不同数据访问技术(Performance Comparison:Data Access Techniques)
    [正则表达式]基础知识总结
    CF623E Transforming Sequence
  • 原文地址:https://www.cnblogs.com/Zfio/p/13637457.html
Copyright © 2011-2022 走看看