Codeforces Round #448 (Div. 2) B. XK Segments【二分搜索/排序/查找合法的数在哪些不同区间的区间数目】

B. XK Segments
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

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 byx.

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).

Input

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.

Output

Print one integer — the answer to the problem.

Examples
input
4 2 1
1 3 5 7
output
3
input
4 2 0
5 3 1 7
output
4
input
5 3 1
3 3 3 3 3
output
25
Note

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.

【题意】: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.

y is divisible by x.(y被x整除)

比如12/4=3,我们就可以说12被4整除,4整除12

A可被B整除,表示A是B的倍数
A可整除B,表示B是A 的倍数

输入 n, x, k  an

找到不同有序下标对(i,j) 满足ai ≤ aj 并且刚好有k个整数 y( ai ≤ y ≤ aj ),y%x==0的数量。

【分析】:二分求上下界,紫薯227页。编码实现不是很难。但是我不是特别懂,希望哪位大佬不吝赐教!右边这个博客解释的比较好,https://www.cnblogs.com/lemonbiscuit/archive/2017/11/27/7903860.html

虽然是连续区间,因为仅仅是求得合法二元组个数,而不是求具体是哪些。将其排序不影响最终结果。
//(官方)First, we need to understand how to find the number of integers in [l, r] segment which are divisible byx. It is r / x–(l - 1) / x. After that we should sort array in ascending order. For each left boundary of the segment l = a[i] we need to find minimal and maximal index of good right boundaries. All right boundaries r = a[j] should satisfy the following condition a[j] / x–(a[i] - 1) / x = k. We already know (a[i] - 1) / x, a[j] / x is increasing while a[j] increases. So we can do binary search on sorted array to find minimal/maximal index of good right boundaries and that mean we can find the number of good right boundaries.


一些大佬的解释:假设现在a[i]是x的倍数的话,设a[i] = t*x,那么要[a[i],a[j]]中有k个x的倍数的话,a[j]的范围就是[(t+k-1)*x,(t+k)*x-1],如果a[i]不是x的倍数的话,设a[i] = t*x + b,那么现在a[j]的范围就是[(t+k)*x,(t+k+1)*x-1],然后用二分找这个范围里的数就好啦。


排序后,选定一个数ai,我们可以根据这个数,和 k 个x的倍数的限制,算出大于等于ai的数的满足条件的范围;比如第一个样例选中了 ai = 3,这是x=2,k=1, (ai/x)就是小于等于ai的x的倍数的个数,aj =(ai/x)*x + x*k 就是满足 i-j 对之间恰好含有k个x的倍数的 一个最小值,当 aj在加上x后,ai - aj 之间就有 k+1个x的倍数了,我们要找的就是给定的数列中 aj 和 (aj+x) 之间的数的个数,这样就求出每个数和大于等于他的数组成的合法对的个数。


先把所有数字升序排序,之后枚举每对点对(i,j)中的 j 。对于一个固定的 j ,满足条件的 i 肯定在已经排序好的数组当中构成了一段连续的区间,且Ai<=Aj。设这段下标区间对应的元素范围为[l,r],则

l=(Ai/x-k)*x+1

r=l+k-1

用stl的lower_bound和upper_bound找到 l r 对应的下标位置即可。需要特别注意k=0的情况,此时 l r是不满足上述公式的,需要特判。


【代码】:

#include <bits/stdc++.h>
using namespace std;
const int maxn =1e5+10;
#define LL long long
LL a[maxn];

int main()
{
   ios::sync_with_stdio(false);
   cin.tie(0);cout.tie(0);
   LL n,x,k,cnt;
   cin>>n>>x>>k;
   for(LL i=0; i<n; i++) cin>>a[i];
   sort(a,a+n);
   cnt=0;

   for(LL i=0;i<n;i++)
   {
       LL left=max( ( (a[i]-1)/x + k )*x, a[i] );
       LL right=( (a[i]-1)/x + k + 1)*x;

       cnt+=lower_bound(a,a+n,right)-lower_bound(a,a+n,left);
   }
   cout<<cnt<<endl;
    return 0;
}
LL 防止爆int
#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

int main()
{
    int n, x, k;
    cin >> n >> x >> k;
    vector<int> a(n);
    
    for (int i = 0; i < n; i++)
        cin >> a[i];
        
    sort(a.begin(), a.end());
    
    long long cnt = 0;
    
    for (int i = 0; i < n; i++) {
        vector<int>::iterator l = lower_bound(a.begin(), a.end(), max((long long)a[i], (long long)x * (k + (a[i] - 1) / x)));
        vector<int>::iterator r = lower_bound(a.begin(), a.end(), max((long long)a[i], (long long)x * (k + 1 + (a[i] - 1) / x)));
        
        cnt += r - l;
    }
    
    cout << cnt;
}
cf一位大佬
原文地址:https://www.cnblogs.com/Roni-i/p/7905287.html