CodeForces - 895B 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).

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

题目大意 对于数组a,整数x,k,求在a里面的数对[ a[i] , a[j] ]的个数,使其满足:
1)a[i] <= a[j]
2)[ a[i] , a[j] ]区间里的数,有k个x的倍数。

思路其实是一道思维题,因为是求数对的个数,所以先排序,没有影响。对于每个a[i],去找比他大的第k小的x的倍数(包括它本身),作为l,比l大的最小的x的倍数,作为r,那么以a[i]为左区间的数对个数就是在a中所有满足 a[j] < r && a[j] >= l 的数都可以当作a[i]的右区间。换句话说 对于每个a[i],我们只需要找到对应的在[l , r)范围内的数的个数即可。l,r的计算式如下:

l = (a[i] / x + k) * x;
r = l + x;

但是对于a[i]整除x的情况,比它大的第k小的倍数就要小一个x了(因为包括它本身),即:

if (a[i] % x == 0) {
    l = a[i] + (k - 1) * x;
} else {
    l = (a[i] / x + k) * x;
}

这样答案就出来了,但是由于数据规模大,会超时,会爆int(血的教训啊!!!),所以我们需要用二分优化一下。二分代码如下:

ans += lower_bound(a + 1, a + n + 1, r) - lower_bound(a + 1, a + n + 1, l);

你以为这样就完了吗?还要考虑 k = 0 的情况!!!(又是血的教训。。。)对于k = 0,如果a[i] 可以整除x,那么以a[i]为左区间的所有数对都不满足要求(因为都会带着a[i]),如果a[i]不可以整除x, l,r 的取值要有所改变,计算式如下:

if (k == 0){
    if (a[i] % x ==0){
        continue;
    }
    l = a[i];
    r = (a[i] / x + 1) * x;
}

这样就可以避免k = 0的WA了。

附赠完整AC代码

#include <iostream>
#include <algorithm>
using namespace std;

long long a[100005];

int main() {
    long long n, x, k;
    while (cin >> n >> x >> k) {
        long long ans(0);
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
        }
        sort(a + 1, a + n + 1);
        for (int i = 1; i <= n; i++) {
            long long l, r;
            if (a[i] % x == 0) {
                l = a[i] + (k - 1) * x;
            } else {
                l = (a[i] / x + k) * x;
            }
            r = l + x;
            if (k == 0){
                if (a[i] % x ==0){
                    continue;
                }
                l = a[i];
                r = (a[i] / x + 1) * x;
            }
            ans += lower_bound(a + 1, a + n + 1, r) - lower_bound(a + 1, a + n + 1, l);
        }
        cout << ans << endl;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值