Codeforces Round 995 (Div. 3)(补题)
Codeforces Round 995 (Div. 3)
D. Counting Pairs(离散化+二分)
题目描述
给你一个由 \(n\) 个整数组成的序列 \(a\) ,其中序列的 \(i\) -th 元素等于 \(a_i\) 。同时还给出两个整数 \(x\) 和 \(y\) ( \(x \le y\) )。
如果满足以下条件,一对整数 \((i, j)\) 就会被认为是有趣的:
- \(1 \le i < j \le n\) ;
- 如果同时从序列 \(a\) 中删除位置 \(i\) 和 \(j\) 的元素,则剩余元素的和至少为 \(x\) ,最多为 \(y\) 。
你的任务是确定给定序列 \(a\) 中有趣的整数对的数目。
输入
第一行包含一个整数 \(t\) ( \(1 \le t \le 10^4\) ) - 测试用例数。
每个测试用例包含两行:
- 第一行包含三个整数 \(n, x, y\) ( \(3 \le n \le 2 \cdot 10^5\) , \(1 \le x \le y \le 2 \cdot 10^{14}\) );
- 第二行包含 \(n\) 个整数 \(a_1, a_2, \dots, a_n\) ( \(1 \le a_i \le 10^{9}\) )。
输入的附加限制:所有测试用例中 \(n\) 的总和不超过 \(2 \cdot 10^5\) 。
输出
对于每个测试用例,输出一个整数 - 给定序列 \(a\) 中有趣的整数对的数量。
Example
Input
7
4 8 10
4 6 3 6
6 22 27
4 9 6 3 4 5
3 8 10
3 2 1
3 1 1
2 3 4
3 3 6
3 2 1
4 4 12
3 3 2 1
6 8 8
1 1 2 2 2 3
Output
4
7
0
0
1
5
6
思路
首先是推公式
设序列为数组\(A\), 设\(S = \sum_1^n A[i]\)
则 \(x \le S - A[i] - A[j] \le y\)
可以得到:\(S - y - A[i]\le A[j] \le S - x - A[i]\)
所以,我们可以枚举\(A[i]\)得到\(A[j]\)的范围,进而计算出\(A[j]\)的个数,查找范围可以二分,但是由于数据范围太大,正常的二分肯定不行,所以要对数据进行离散化处理。
要注意的是前前后后并没有判断\(i\)和\(j\)的大小关系,所以\(i < j\)、\(i = j\)、\(i > j\)的答案都会计算出来,只需要最后减去后面两个就行
评述:
非常有参考价值的一道题,值得多想
代码
#include <bits/stdc++.h>
typedef std::pair<int, int> pii;
#define INF 0x3f3f3f3f
#define MOD 998244353
using i64 = long long;
const int N = 1e5+5;
void solve(){
i64 n, x, y;
std::cin >> n >> x >> y;
i64 S = 0;
std::vector<i64> A(n), B(3*n+1);
std::vector<i64> dct;
dct.push_back(-1E18); // 防止越界加的哨兵
for (int i = 0; i < n; i++) {
std::cin >> A[i];
S += A[i];
}
for (int i = 0; i < n; i++){
dct.emplace_back(A[i]);
dct.emplace_back(S - x - A[i]);
dct.emplace_back(S - y - A[i]);
}
sort(dct.begin(), dct.end());
dct.erase(std::unique(dct.begin(), dct.end()), dct.end());
auto find = [&](i64 p) -> i64{
return std::lower_bound(dct.begin(), dct.end(), p) - dct.begin();
};
for (int i = 0; i < n; i++){
B[find(A[i])] += 1;
}
for (int i = 1; i < 3*n+1; i++){
B[i] += B[i-1];
}
i64 res = 0, ans = 0;
for (int i = 0; i < n; i++){
res += B[find(S-x-A[i])] - B[find(S-y-A[i]) - 1];
if (S - A[i] - A[i] >= x && S - A[i] - A[i] <= y) ans ++;
}
std::cout << (res - ans) / 2 << '\n';
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(2);
int t = 1, i;
std::cin >> t;
for (i = 0; i < t; i++){
solve();
}
return 0;
}

浙公网安备 33010602011771号