2016多校联合第二场 HDU5741解题报告
来源:互联网 发布:学校网络设计方案 编辑:程序博客网 时间:2024/05/22 02:16
题意:给你一个数组,v[i] 表示:当i为偶数是表示0的个数,当i为奇数是表示1的个数。然后要你查询一堆区间,是否能找到某个区间[l,r] 使得0的个数等于a ,1的个数等于b
题解说的很奇妙,涨了姿势。我们可以这么想,对于一个确定的a ,那么必然存在一段区间[bl,br] 那就可以抽象成一连串离散的点集了(设a是横坐标,b是纵坐标 )
上图是整理过点集后的图片,一开始都是一条x,y 递增的线段,每个红点设成low 点(低点),绿点设成up 点,蓝色的点可以不管(以a 开始a 结尾的点是红点,b 开始b 结尾的点是绿点)
对于low 中的点按照x 排序之后,显然为了让解区间更大,倾向于选择y 最低的点,当遍历到更大的x ,若出现的y较小,因为都是从(0,0) 点连过来的,必然可以用此点代替较小的x 却具有较大的y 的点
low 点的整理过程就是上面所描述的,然后是up 点的整理
同样按照x 排序,对于同样的x 肯定选择更大的点使得解空间最优对于x 比较大的点,我们选取比当前点集y 最大的还要大的点加入点集,可能这里有些读者会存在问题,有些y 比较大,但是x 却比较小的点怎么办。这是不可能存在的,可以证明。若比较大的a 在此点开始的后面显然不存在,若比较大的a 在此点开始的前面,那么此点开始的前面肯定会具有更大的b 矛盾。所以不存在这样的点。(所谓开始就是在原数组中的开始累加的地方)
处理完两个点集后,我们就可以扫描线了。对于每个查询,找到low 中大于等于a 的点,在up 中找到横坐标小于等于a 的点,然后判断下b 是否在二者区间内就行了
//// Created by Running Photon// Copyright (c) 2015 Running Photon. All rights reserved.//#include <algorithm>#include <cctype>#include <cmath>#include <cstdio>#include <cstdlib>#include <cstring>#include <iomanip>#include <iostream>#include <map>#include <queue>#include <string>#include <sstream>#include <set>#include <vector>#include <stack>#define ALL(x) x.begin(), x.end()#define INS(x) inserter(x, x,begin())#define ll long long#define CLR(x) memset(x, 0, sizeof x)using namespace std;const int inf = 0x3f3f3f3f;const int MOD = 2e9 + 7;const int maxn = 5e5 + 10;const int maxv = 1e3 + 10;const double eps = 1e-9;int a[maxv];struct Point { int x, y; Point (int _x = 0, int _y = 0) : x(_x), y(_y) {} void print() { printf("%d %d\n", x, y); } bool operator< (const Point& rhs) const { if(x == rhs.x) return y < rhs.y; return x < rhs.x; } bool operator== (const Point& rhs) const { return x == rhs.x && y == rhs.y; }}low[maxn], upp[maxn];int main() {#ifdef LOCAL freopen("C:\\Users\\Administrator\\Desktop\\in.txt", "r", stdin);// freopen("C:\\Users\\Administrator\\Desktop\\out.txt","w",stdout);#endif// ios_base::sync_with_stdio(0); int T; scanf("%d", &T); while(T--) { int n, q; scanf("%d%d", &n, &q); for(int i = 0; i < n; i++) scanf("%d", &a[i]); int lowCnt = 0, uppCnt = 0; for(int i = 0; i < n; i++) { int addx = 0, addy = 0; for(int j = i; j < n; j++) { if(j & 1) addy += a[j]; else addx += a[j]; if((i & 1) && (j & 1)) { upp[uppCnt++] = Point(addx, addy); } if(i % 2 == 0 && j % 2 == 0) { low[lowCnt++] = Point(addx, addy); } } } sort(low, low+lowCnt); n = 0; for(int i = 0, j; i < lowCnt; i = j) { for(j = i; j < lowCnt && low[i].x == low[j].x; j++); while(n > 0 && low[n - 1].y >= low[i].y) n--; low[n++] = low[i]; } lowCnt = n; n = 0; sort(upp, upp+uppCnt); for(int i = 0, j; i < uppCnt; i = j) { for(j = i; j < uppCnt && upp[i].x == upp[j].x; j++); if(!n || upp[n - 1].y < upp[j - 1].y) upp[n++] = upp[j - 1]; } uppCnt = n; for(int i = 1; i <= q; i++) { int a, b; scanf("%d%d", &a, &b); int x = upper_bound(upp, upp + uppCnt, Point(a, inf)) - upp; int y = upper_bound(low, low + lowCnt, Point(a, -inf)) - low; printf("%c", '0' + (y < lowCnt && upp[x - 1].y >= b && low[y].y <= b)); } puts(""); } return 0;}
0 0
- 2016多校联合第二场 HDU5741解题报告
- 2016多校联合第二场 HDU5739 Fantasia 解题报告
- 2016多校联合第二场 HDU5735 Born Slippy 解题报告
- 2016多校联合第一场 HDU5731解题报告
- 2013年HDU多校联合第三场解题报告
- HDU 4876 ZCC loves cards (2014多校联合训练第二场1005) 解题报告(暴力+剪枝)
- 2016多校联合第二场
- HDU/杭电2013多校第二场解题报告
- HDU 4864 Task (2014多校联合训练第一场1004) 解题报告(贪心)
- [HDU5741] Helter Skelter [2016 Multi-University Training Contest 2(2016多校联合训练2) H]
- 多校联合 第二场 A
- 多校联合 第二场 E DP
- [HDU3974] 解题报告 && 多校联合反思
- 130725hdu杭电多校第二场解题报告
- bo_jwolf不卖萌的第二场解题报告
- HDU 4869 Turn the pokers (2014多校联合训练第一场1009) 解题报告(维护区间 + 组合数)
- 多校第七场解题报告
- 多校第八场解题报告
- IOS点击底部tabbar的事件
- UVA 10285(DFS)
- 不使用正则表达式 匹配字符串(字母)
- Spinner
- 链接地址学习笔记
- 2016多校联合第二场 HDU5741解题报告
- linux安装部署git
- 人生如牌
- Git 常用命令
- Postgresql uuid,pgtrashcan,pldebugger install
- @override 下划线
- autocomplete="off"
- 排列组合公式
- 16标准(键盘,控制台)输入输出流