D. Pair of Topics


D. Pair of Topics


标签

  • 思维

简明题意

  • 给定两个n长数组a和b。需要找出满足 i < j , a i + a j < b i + b j ii<j,ai+aj<bi+bj的数量。

思路

  • 我们移项一下,发现是要找 i < j , a i − b i < − ( a j − b j ) ii<j,aibi<(ajbj)
  • 我们令c[]数组为a数组和b的差。上式就变成 i < j , c i < − c j ii<j,ci<cj
  • 那么很自然的想法,就是在每一个c[i]后面找值小于 − c i -c_i ci的数的数量。这样想,相当于一个在线算法,做法是:权值线段树维护值在某个范围内的数量有多少个。在我们一依次向后考虑每个i的时候,就把前面的a[i]从权值线段树中删掉。然后注意一下要把负数偏移一下,a[i]是1e9的还要离散化一下。很复杂
  • 考虑离线做法。 按照 i < j , c i < − c j ii<j,ci<cj这个式子想,我们就进入误区了。我们实际可以发现,可以这样求: i < j , c i + c j < 0 ii<j,ci+cj<0的对数。这样的话,就和位置无关了,这实际找的就是数列中和<0的对数,那么我们可以随意打乱数组的顺序。
  • 那么就可以给数组排序,对每一个数,在它后面寻找和这个数<0的数有多少。
  • 这里就有两种做法了,我们可以枚举每一个数,二分找。
  • 注意到我们枚举的数是依次递增的,这就类似二维偏序。假设有两个集合,一个是所有的枚举了的数,一个是还没有被枚举的数,那么枚举了的数越大,相应备选的数就越少,而且是在原来基础上越少。 (口胡的忽略就好) 然后就双指针呗,一直往前就好(我觉得双指针是一种二维偏序,或者说很相似)

注意事项


总结

  • 搞清楚lower_bound()-a中-a得到的是啥。不管lowerbound中第一个参数是a加多少,-a的到的都是:找到的那个元素的下标。
  • 题目要求二元组,要是有下标限制,那么我们可以试着转换一下,让其没有下表限制,从而离线做。

AC代码

二分做法

#pragma GCC optimize(2)
#include
#include
#include
#include 
#include
#include
#include
#include	
#include
#include
#include
using namespace std;

const int maxn = 2e5 + 10;

int a[maxn];

void solve()
{
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++)
		cin >> a[i];
	for (int i = 1; i <= n; i++)
	{
		int t;
		cin >> t;
		a[i] -= t;
	}

	sort(a + 1, a + 1 + n);

	long long ans = 0;
	for (int i = 1; i <= n; i++)
		ans += n -(upper_bound(a + i + 1, a + 1 + n, -a[i]) - a) + 1;
	cout << ans;
}
	
int main()
{
	//freopen("Testin.txt", "r", stdin);
	solve();
	return 0;
}

双指针做法

#pragma GCC optimize(2)
#include
#include
#include
#include 
#include
#include
#include
#include	
#include
#include
#include
using namespace std;

const int maxn = 2e5 + 10;

int a[maxn];

void solve()
{
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++)
		cin >> a[i];
	for (int i = 1; i <= n; i++)
	{
		int t;
		cin >> t;
		a[i] -= t;
	}

	sort(a + 1, a + 1 + n);

	long long ans = 0;
	int r = n;
	for (int i = 1; i <= n; i++)
	{
		while (a[i] + a[r] > 0)
			r--;
		ans += min(n - r, n - i);
	}
	cout << ans;
}
	
int main()
{
	//freopen("Testin.txt", "r", stdin);
	solve();
	return 0;
}

你可能感兴趣的:(思维)