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;
}
posted @ 2024-12-23 21:29  califeee  阅读(311)  评论(1)    收藏  举报