codeforces895B XK segments

蛮有趣的一道题。
先来说说题意,大概是:对一个数组a,定义符合条件的二元组 (i,j) 表示恰好存在 k 个整数,满足aiyaj y x的倍数,求符合条件的二元组数量。


一上来有些懵逼,不妨先找找规律。
我们知道,假定存在 k 个这样的整数,那么首先[L,L+(k1)x]一定是符合条件的一个区间,然后考虑拓展,右端点范围应当是 [L+(k1)x,L+kx1] ,因为这个时候一定能找到符合条件的 k 个整数。
接下来的问题就是如何找到L。假如 a[i] 不是 x 的倍数,那么a[i]本身不会算到 k 个数中间去,所以此时L=(a[i]/x+1)x;否则, a[i] 也是 k 的一份子,所以L=a[i]
对数组排序之后,我们可以遍历一遍整个数组,然后对每一个数求一下在 [L+(k1)x,L+kx1] 范围内有多少数即可。
最后考虑如何实现。由于我们只是统计个数,所以我们可以二分查找出 l=L+(k1)x r=L+kx 第一个大于等于这两个数的数所在的位置相减即可。可以采用algorithm库的lower_bound实现。
当然这样有个问题,就是对k = 0的情况应当有一些特判,此时我们发现如果 a[i] x 的倍数,区间就是a[i],a[i]那么结果为0,而此时 L=a[i] ;否则区间应当是 a[i],L ,此时由于 k=0 所以 L=r ,所以只需要对 l <script type="math/tex" id="MathJax-Element-4431">l</script>加一个特判即可。


AC代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
LL a[100003], ans;
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    LL n, x, k;
    cin>>n>>x>>k;
    for(int i = 1; i <= n; ++i) cin>>a[i];
    sort(a + 1, a + n + 1);
    for(int i = 1; i <= n; ++i) {
        LL L = (a[i] % x) ? ((a[i] / x + 1) * x) : a[i];
        LL l = L + (k - 1) * x, r = L + k * x;
        if(!k) l = a[i];
        ans += lower_bound(a + 1, a + n + 1, r) - lower_bound(a + 1, a + n + 1, l);
    }
    cout<<ans<<endl;
    return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值