1009 Triple Inversions (35 分)(C++)

欢迎访问我的PAT顶级题解目录

Given a list of N integers A​1​​, A​2​​, A​3​​,...A​N​​, there's a famous problem to count the number of inversions in it. An inversion is defined as a piar of indices i<j such that A​i​​>A​j​​.

Now we have a new challenging problem. You are supposed to count the number of triple inversions in it. As you may guess, a triple inversion is defined as a triple of indices i<j<k such that A​i​​>A​j​​>A​k​​. For example, in the list { 5, 1, 4, 3, 2 } there are 4 triple inversions, namely (5,4,3), (5,4,2), (5,3,2) and (4,3,2). To simplify the problem, the list A is given as a permutation of integers from 1 to N.

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integer N in [3,10​5​​]. The second line contains a permutation of integers from 1 to N and each of the integer is separated by a single space.

Output Specification:

For each case, print in a line the number of triple inversions in the list.

Sample Input:

22
1 2 3 4 5 16 6 7 8 9 10 19 11 12 14 15 17 18 21 22 20 13

Sample Output:

8

题目大意:给出一个长为n的序列(序列为1-n的某种排列),求给定序列中有多少个三元递减序列

解题思路:遍历,将每个数看为中间那个数字,只要求出该数左边有多少比它大的数,右边有多少比它小的数,两个数目相乘即可。

left记录该数左边有多少比它大的数

right记录右边有多少比它小的数

树状数组

树状数组维护的C,C[i]表示原数组A中数组为 i 出现了C[i]次

每次插入时,用树状数组的getNum查询当前(该数左边)有多少比它小的数,,通过简单的运算就可以算出left和right的值

#include <bits/stdc++.h>
#define lowbit(i) ((i) & (-i))
using namespace std;
const int maxn = 100010;
int c[maxn];
void update(int x, int val){
	for(int i = x; i < maxn; i += lowbit(i))
		c[i] += val;
}
int getSum(int x){
	int ans = 0;
	for(int i = x; i >= 1; i -= lowbit(i))
		ans += c[i];
	return ans;
}
int main(){
	int n; 
	long long int left, right, ans = 0;
	scanf("%d", &n);
	vector<int> a(n);
	for(int i = 0; i < n; ++ i){
		scanf("%d", &a[i]);
		update(a[i], 1);
		left = i + 1 - getSum(a[i]);
		right = a[i] - getSum(a[i] - 1) - 1;
		ans += left * right;
	}
	printf("%lld", ans);
}

平衡二叉树

我们的目的是要针对数组中某个数,求该数的左边比它大的个数,右边比他小的个数,时间代价尽可能小,除了树状数组,平衡树也可以满足我们的需求。

可以调用pb_ds库,具体使用可以参考平板电视库

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
using namespace std;
using namespace __gnu_pbds;
int main(){
	tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> tr;
	int n, temp;
	long long int left, right, ans = 0;
	scanf("%d", &n);
	for(int i = 0; i < n; ++ i){
		scanf("%d", &temp);
		tr.insert(temp);
		left = i - tr.order_of_key(temp);
		right = temp - tr.order_of_key(temp) - 1;
		ans += left * right; 
	}
	printf("%lld", ans);
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章