CF895B XK Segments 题解
CF895B XK Segments 题解
题目描述
题目解法
朴素想法
最简单的想法就是枚举二元组 \((i,j)\) 的第一项 \(i\),然后再枚举 \(j\),找到一个满足条件的 \(a_j\),然后更新答案。
很明显,该做法的时间复杂度为 \(O(n^2)\),无法通过本题。
二分
我们发现,\(a\) 数组不会更改,并且每次枚举 \(a_j\) 的过程相当于查找符合条件的区间中元素的个数。
先算出大于等于 \(a_i\) 的第一个 \(x\) 的倍数 \(a_i\)。
\[\begin{cases}
a_i'=(\lfloor \frac{a_i}{x} \rfloor + 1)\times x & (a_i \not\equiv 0 \mod x)\\
a_i'=a_i & (a_i \equiv 0 \mod x)
\end{cases}
\]
符合条件的区间的左端点 \(l=a_i'+(k-1)\times x\)。
符合条件的区间的右端点 \(r=a_i'+k\times x\)。
记得特判 \(k=0\) 的情况。
先排序再二分端点,迭代器相减即可。
记得开 long long
。
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n, x, k;
vector<int> vc;
signed main()
{
cin>>n>>x>>k;
int ans=0;
for(int i=1, v;i<=n;i++)
cin>>v, vc.push_back(v);
sort(vc.begin(), vc.end());
for(auto i:vc)
{
int nx=(i%x)?(i/x+1)*x:i;
int l=k?nx+(k-1)*x:i, r=nx+k*x;
auto it1=lower_bound(vc.begin(), vc.end(), r);
auto it2=lower_bound(vc.begin(), vc.end(), l);
ans+=it1-it2;
}
cout<<ans;
}