PAT 1009. Triple Inversions (35) 数状数组
Given a list of N integers A1, A2, A3,...AN, there's a famous problem to count the number of inversions in it. An inversion is defined as a pair of indices i < j such that Ai > Aj.
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 Ai > Aj > Ak. 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, 105]. 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
题意:给定1~n的无序数列,求其中长度=3连续递减的字串个数,如样例:(16,14,13)。
思路:愚蠢!愚蠢!刚开始找的是三个数中的最前一个,然而判断连续递减就有点困难(这题时间限制为300ms)。
其实可以找中间的那个数,再向左查询比中间数大的数的个数,向右查询比中间数小的个数, 两侧相乘就是解了。
最大的问题是如何记录大小,因为给定的是1~n连续的数,甚至不需用离散化,通过遍历到某个数,找比它小或大的是否已经被标记了,再标记这个数。
快速求和操作显然要用到树状数组。
噢,还有这题注意结果使用long long 为此而WA。
1 #include <stdio.h> 2 #include <iostream> 3 #include <string.h> 4 #include <algorithm> 5 #define LL long long 6 using namespace std; 7 8 9 int n, c[100010], a[100010]; 10 LL l[100010], r[100010]; 11 void add(int x) //增加操作 12 { 13 while(x <= n) 14 { 15 c[x]++; 16 x += x & (-x); 17 } 18 } 19 20 int get(int x) //获取和 21 { 22 int ans = 0; 23 while(x) 24 { 25 ans +=c[x]; 26 x -= x & (-x); 27 } 28 return ans; 29 } 30 int main() 31 { 32 LL ans; 33 while(cin >> n) 34 { 35 ans = 0; 36 for(int i = 1; i <= n; i++) 37 { 38 scanf("%d", a + i); 39 c[i] = 0; 40 } 41 for(int i = 1; i <= n; i++) 42 { 43 l[i] = i - 1 - get(a[i]); 44 add(a[i]); 45 } 46 for(int i = 1; i <= n; i++) 47 c[i] = 0; 48 for(int i = 1; i <= n; i++) 49 { 50 r[i] = a[i] - 1 - get(a[i]);//为value - 左侧大于它的个数 51 add(a[i]); 52 } 53 54 for(int i = 1; i <= n; i++) 55 ans += l[i]*r[i]; 56 57 printf("%lld\n", ans); 58 } 59 }