Description
一个可重复数字集合S的神秘数定义为最小的不能被S的子集的和表示的正整数。例如S={1,1,1,4,13},
“`
1 = 1
2 = 1+1
3 = 1+1+1
4 = 4
5 = 4+1
6 = 4+1+1
7 = 4+1+1+1
“`
8无法表示为集合S的子集的和,故集合S的神秘数为8。
现给定n个正整数a[1]..a[n],m个询问,每次询问给定一个区间l,r,求由a[l],a[l+1],…,a[r]所构成的可重复数字集合的神秘数。
Input
第一行一个整数n,表示数字个数。
第二行n个整数,从1编号。
第三行一个整数m,表示询问个数。
以下m行,每行一对整数l,r,表示一个询问。
Output
对于每个询问,输出一行对应的答案。
Sample Input
“`
5
1 2 4 9 10
5
1 1
1 2
1 3
1 4
1 5
“`
Sample Output
“`
2
4
8
8
8
“`
HINT
对于100%的数据点,n,m <= 100000,∑a[i] <= 10^9
Source
Solution
假设区间固定?
首先考虑暴力做法,询问区间l,r时,将a中的l到r这一部分元素取出,排序后求前缀和pre找第一个ai > prei + 1的i,然后prei + 1就是答案了;
如果我们预先知道了pre,和排序后的a,能不能小于O(n)的时间内求出来i?
有个看上去比较low的想法,当我们在i时,我们用pre二分一个最大的aj使得我们在i一步能跳到j
不断的二分+跳直到跳不动为止,此时就是答案。
看上去复杂度要爆炸?
其实不然 因为两部之内,aj会增长一倍多!
为什么呐??
考虑从p1跳到p2然后跳到p3这个过程
ap3+1 > prep1 + ap2
而ap2 ≥ prep1
所以ap3+1 > 2*prep1
所以最多跳⌊log(10^9)⌋次
怎么强行排序?权值线段树!
然后需要实现在权值线段树上二分
题目变成了给你一棵权值线段树,你只能用支持加法的合并操作来搞出支持询问小于x的数的和是多少。
这个做法比较简单,留给读者自己练习。
但是区间不是固定的,我们可持久化这棵线段树就好啦
Code
| |