1. 题意
给定一个长度为 N N N 的整数列表 A A A ,其中所有 A i A_i A i 互不相同。
对于每个询问 ( X , Y ) (X,Y) ( X , Y ) ,要求在所有大于等于 X X X 且不在列表 A A A 中的整数里,找到第 Y Y Y 小的数。
N , Q ≤ 3 × 10 5 N,Q \le 3\times 10^5 N , Q ≤ 3 × 1 0 5 ,1 ≤ A i , X , Y ≤ 10 9 1\le A_i,X,Y\le 10^9 1 ≤ A i , X , Y ≤ 1 0 9 。
2. 思路
这个数据规模,直接从 X X X 开始枚举肯定会 TLE,所以我的第一反应是二分答案。
对于一个整数 v v v 来说,设 f ( v ) = v − ∣ { a i ∣ a i ≤ v } ∣ f(v) = v - |\{ a_{i} \mid a_{i} \le v \}| f ( v ) = v − ∣ { a i ∣ a i ≤ v } ∣ 表示不超过 v v v 的正整数中,有多少个整数不在 A A A 数组中。
如果直接二分答案 a n s ans an s ,那么对于询问 ( X , Y ) (X, Y) ( X , Y ) ,需要找到最小的 a n s ans an s ,满足区间 [ X , a n s ] [X, ans] [ X , an s ] 中至少有 Y Y Y 个缺失数,也就是 f ( a n s ) − f ( X − 1 ) ≥ Y f(ans) - f(X - 1) \ge Y f ( an s ) − f ( X − 1 ) ≥ Y 。
这个做法是可行的,但还可以继续优化。继续观察这个式子可以发现,每次询问真正需要的并不是区间本身,而是缺失数在全体正整数中的排名。
设小于 X X X 的缺失数的个数为 m i s s miss mi ss ,那么大于等于 X X X 的第 Y Y Y 个缺失数,就等价于全体正整数中的第 m i s s + Y miss + Y mi ss + Y 个正整数。
因此对于询问 ( X , Y ) (X, Y) ( X , Y ) ,先计算 k = m i s s + Y k = miss + Y k = mi ss + Y ,然后就把问题变成了:求全体正整数中第 k k k 个缺失数。
将 A A A 排序后,考虑第 i i i 个已有数字 a i a_i a i 。
在 1 1 1 到 a i a_i a i 之间,一共有 a i a_i a i 个正整数,其中有 i i i 个数出现在列表 A A A 中,所以不超过 a i a_{i} a i 的缺失数数量为:a i − i a_i-i a i − i ,我们将其记为 b b b 数组:b i = a i − i b_{i} = a_{i} - i b i = a i − i 。
由于 a i a_i a i 严格递增,有:
b i + 1 − b i = ( a i + 1 − ( i + 1 ) ) − ( a i − i ) = a i + 1 − a i − 1 ≥ 0 b_{i+1}-b_i=(a_{i+1}-(i+1))-(a_i-i)=a_{i+1}-a_i-1\ge 0
b i + 1 − b i = ( a i + 1 − ( i + 1 )) − ( a i − i ) = a i + 1 − a i − 1 ≥ 0
所以数组 b b b 是单调不降的,可以对它进行二分。
对于一次询问 ( X , Y ) (X,Y) ( X , Y ) ,先在 A A A 中找到第一个满足 a p o s x ≥ X a_{posx}\ge X a p os x ≥ X 的位置,记为 posx。
由于我的数组采用 1 1 1 下标,所以小于 X X X 的已有数字个数为 p o s x − 1 posx-1 p os x − 1 ,小于 X X X 的正整数总数为 X − 1 X-1 X − 1 。
因此小于 X X X 的缺失数个数为:m i s s = ( X − 1 ) − ( p o s x − 1 ) = X − p o s x miss = (X - 1) - (posx - 1) = X - posx mi ss = ( X − 1 ) − ( p os x − 1 ) = X − p os x 。
目标就是全体正整数中的第:k = m i s s + Y k = miss + Y k = mi ss + Y 个缺失数。
接下来在 b b b 中找到第一个满足 b p o s ≥ k b_{pos}\ge k b p os ≥ k 的位置,记为 pos:
因为 b p o s b_{pos} b p os 表示不超过 a p o s a_{pos} a p os 的缺失数数量,所以第 k k k 个缺失数一定在 a p o s − 1 a_{pos-1} a p os − 1 到 a p o s a_{pos} a p os 之间。
设答案为 a n s ans an s ,在 1 1 1 到 a n s ans an s 中,一共有:k k k 个缺失数;p o s − 1 pos-1 p os − 1 个出现在列表 A A A 中的数。
所以:a n s = k + ( p o s − 1 ) ans = k + (pos - 1) an s = k + ( p os − 1 )
最终复杂度为:O ( N log ( N ) + Q log ( N ) ) \mathcal{O}(N \log(N) + Q \log(N)) O ( N log ( N ) + Q log ( N )) 。
3. 代码部分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 ll read ( ) { } ll a[maxn], b[maxn];void solve ( ) { int n = read ( ), q = read ( ); for ( int i = 1 ; i <= n; ++ i ) a[i] = read ( ); sort ( a + 1 , a + n + 1 ); for ( int i = 1 ; i <= n; ++ i ) b[i] = a[i] - i; for ( int i = 1 ; i <= q; ++ i ) { ll x = read ( ), y = read ( ); int posx = lower_bound ( a + 1 , a + n + 1 , x ) - a; ll miss = x - posx; ll k = y + miss; int pos = lower_bound ( b + 1 , b + n + 1 , k ) - b; ll ans = k + ( pos - 1 ); cout << ans << '\n' ; } }
4. 复盘