Codeforces 895.B XK Segments
While Vasya finished eating his piece of pizza, the lesson has already started. For being late for the lesson, the teacher suggested Vasya to solve one interesting problem. Vasya has an array a and integer x. He should find the number of different ordered pairs of indexes (i, j)such that ai ≤ aj and there are exactly k integers y such that ai ≤ y ≤ aj and y is divisible by x.
In this problem it is meant that pair (i, j) is equal to (j, i) only if i is equal to j. For example pair (1, 2) is not the same as (2, 1).
The first line contains 3 integers n, x, k (1 ≤ n ≤ 105, 1 ≤ x ≤ 109, 0 ≤ k ≤ 109), where n is the size of the array a and x and k are numbers from the statement.
The second line contains n integers ai (1 ≤ ai ≤ 109) — the elements of the array a.
Print one integer — the answer to the problem.
4 2 1
1 3 5 7
3
4 2 0
5 3 1 7
4
5 3 1
3 3 3 3 3
25
In first sample there are only three suitable pairs of indexes — (1, 2), (2, 3), (3, 4).
In second sample there are four suitable pairs of indexes(1, 1), (2, 2), (3, 3), (4, 4).
In third sample every pair (i, j) is suitable, so the answer is 5 * 5 = 25.
大致题意:求有多少对(i,j),使得a[i]到a[j]之间x的倍数恰好有k个,a[i] ≤ a[j].
分析:我的做法是比较套路的二分加速枚举区间.
先将a数组排序,这样就消除了a[i] ≤ a[j]这个限制,然后枚举左端点,在左端点右边进行二分.二分出倍数正好为k个的下界l和上界r,接下来的统计有点麻烦.如果二分得到的区间正好包含了i,那么答案要-1,因为(i,i)不能被统计两次.接着,还要求出一个区间[i,p],使得这个区间中的所有数都等于a[i].如果这个区间中的每一个数和a[i]都满足要求,那么(i,j)和(j,i)实质上是一样的,答案要*2,剩下的只需要加上区间长度就好了.
这种写法比较繁琐,一个比较好的处理方法是二分的不仅仅局限于i右边的区间,而是被包含整个区间的区间.
#include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; ll n, x, k, a[100010], ans; ll solve(ll p, ll q) { return a[q] / x - (a[p] - 1) / x; } int main() { cin >> n >> x >> k; for (ll i = 1; i <= n; i++) cin >> a[i]; sort(a + 1, a + 1 + n); for (ll i = 1; i <= n; i++) { ll l = i, r = n, ans1 = i; while (l <= r) { ll mid = (l + r) >> 1; if (solve(i, mid) >= k) { ans1 = mid; r = mid - 1; } else l = mid + 1; } ll ans2 = n; l = i, r = n; while (l <= r) { ll mid = (l + r) >> 1; if (solve(i, mid) <= k) { ans2 = mid; l = mid + 1; } else r = mid - 1; } l = i, r = n; ll ans3 = i; while (l <= r) { ll mid = (l + r) >> 1; if (a[mid] > a[i]) r = mid - 1; if (a[i] == a[mid]) { l = mid + 1; ans3 = mid; } } if (solve(i, ans1) == k && solve(i, ans2) == k) { if (ans3 < ans1) ans += (ans2 - ans1 + 1); else { ans += (ans3 - ans1 + 1) * 2; ans += (ans2 - ans3); if (ans1 == i) ans--; } } } cout << ans << endl;
return 0; }