題目連結:https://codeforces.com/problemset/problem/895/B
題目大意
給你一個長度為 \(n\) 的數列 \(a_1, a_2, \ldots, a_n\)。求數列中存在多少個不同的下標對 \((i, j)\) 滿足如下條件:
\(a_i \le a_j\) 並且恰好有 \(k\) 個整數 \(y\) 滿足 \(a_i \le y \le a_j\) 且 \(y\) 能被 \(x\) 整除。
注:在本題中,若 \(i \neq j\),則下標對 \((i, j)\) 和下標對 \((j, i)\) 是不同的下標對。
解題思路
首先我們可以將 \(a_1 \sim a_n\) 從小到大排序。
很明顯排序前後的下標對數量不會變化。
但是排序後和下標 \(i\) 構成滿足條件的下標對 \((i, j)\) 的下標 \(j\) 將會在一個連續的範圍內。
其次要注意,本題中資料處理的過程中可能會發生超出 int 範圍的情況,所以乾脆全部都開 long long。即:
#define int long long
然後我們就可以列舉每個下標 \(i\),判斷 \(a_i\) 開始(即下標 \(i, i+1, i+2, \ldots, n\) 範圍內)存在多少個下標 \(j\) 滿足
\(a_i \le a_j\) 並且恰好有 \(k\) 個整數 \(y\) 滿足 \(a_i \le y \le a_j\) 且 \(y\) 能被 \(x\) 整除。
這個條件,然後把數量加起來就可以了。
具體來說:
- 當 \(i = 1\) 時,判斷 \([1, n]\) 範圍記憶體在多少下標 \(j\) 和 \(i\) 構成的下標對 \((i, j)\) 滿足上述條件;
- 當 \(i = 2\) 時,判斷 \([1, n]\) 範圍記憶體在多少下標 \(j\) 和 \(i\) 構成的下標對 \((i, j)\) 滿足上述條件;
- ……
- 當 \(i = n\) 時,判斷 \([1, n]\) 範圍記憶體在多少下標 \(j\) 和 \(i\) 構成的下標對 \((i, j)\) 滿足上述條件。
即對於每個下標 \(i\) 判斷區間 \([1, n]\) 範圍記憶體在多少個下標 \(j\) 滿足條件。
在 \(a_i = a_j\) 時,\(j\) 甚至可能小於 \(i\)。
(注意 \(i\) 可以等於 \(j\),即下標對 \((i, i)\) 也可能是滿足條件的)
而且我們會發現,對於每個下標 \(i\),滿足條件的下標 \(j\) 是一個連續的區間,這很好理解:
設滿足條件的 \(j\) 所在的區間為 \([l_i, r_i]\)(而一整個區間是 \([1, n]\)),則:
- 區間 \([1, l_i - 1]\) 範圍內:\(x\) 的倍數 \(\lt k\) 個;
- 區間 \([l_i, r_i]\) 範圍內:\(x\) 的倍數恰好 \(k\) 個;
- 區間 \([r_i + 1, n]\) 範圍內:\(x\) 的倍數 \(\gt k\) 個。
所以我們現在要做的事情就是找 \(i\) 對應的最小值 \(l_i\) 和最大值 \(r_i\)。
有一種特殊情況,\(k = 0\)。
\(k = 0\) 時
此時若 \(a_i\) 是 \(x\) 的倍數,則無解。(因為此時至少有一個 \(a_i\) 是 \(x\) 的倍數)
若 \(a_i\) 不是 \(x\) 的倍數,則 \(l_i = a_i\),\(r_i = \lceil \frac{a_i}{x} \rceil \times x - 1\)。
\(k \gt 0\) 時
\(l_i = \lceil \frac{a_i}{x} \rceil \times x + (k - 1) \times x\)
\(r_i = l_i + x - 1\)
確定好 \(l_i\) 和 \(r_i\) 之後 —— 我們用 l
表示 \(l_i\),用 r
表示 \(r_i\),那麼
lower_bound(a+i, a+n+1, l) - a
對應的就是下標 \(l_i\)。
upper_bound(a+i, a+n+1, r) - a - 1
對應的就是下標 \(r_i\)。
則 \([l_i, r_i]\) 範圍內滿足條件的下標一共有 \(r_i - l_i + 1\) 即:
upper_bound(a+i, a+n+1, r) - lower_bound(a+i, a+n+1, l)
個。
對於每個下標 \(i\),確定好 \(l_i\) 和 \(r_i\) 之後,對上式進行累加即可。
示例程式
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
#define int long long
int n, x, k, a[maxn], ans;
signed main() {
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++) {
int l, r;
if (k == 0) {
if (a[i] % x == 0)
continue;
l = a[i], r = (a[i] + x - 1) / x * x - 1;
}
else {
l = (a[i] + x - 1) / x * x + (k - 1) * x;
r = l + x - 1;
}
ans += upper_bound(a+1, a+n+1, r) - lower_bound(a+1, a+n+1, l);
}
cout << ans << endl;
return 0;
}