[UVALive4329] Ping pong(树状数组,组合)

题目链接:https://vjudge.net/problem/UVALive-4329

题意:n个数,找出三个数ai,aj,ak,使得i<j<k且ai<aj<ak或者ai>aj>ak。问有多少种组合方法。

枚举aj,记cj为[1,j)内比aj小的数的个数,dj为(j,n]比aj小的个数。

那么j-1-cj为[1,j)比aj大的数的个数,n-j-dj为(j,n]比aj大的数的个数。

把答案就是∑dj*(j-1-cj)+(n-j-dj)*cj

用BIT在O(nlgn)就能分别获得c和d。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 typedef long long LL;
 5 const int maxn = 20020;
 6 const int maxm = 100100;
 7 int n, m;
 8 int a[maxn];
 9 LL bit[maxm];
10 LL c[maxm], d[maxm];
11 
12 inline int lowbit(int x) {
13     return x & (-x);
14 }
15 
16 void add(int i) {
17     while(i <= m) {
18         bit[i]++;
19         i += lowbit(i);
20     }
21 }
22 
23 LL sum(int i) {
24     LL ret = 0;
25     while(i) {
26         ret += bit[i];
27         i -= lowbit(i);
28     }
29     return ret;
30 }
31 
32 
33 int main() {
34     // freopen("in", "r", stdin);
35     int T;
36     scanf("%d", &T);
37     while(T--) {
38         scanf("%d", &n);
39         m = -1;
40         for(int i = 1; i <= n; i++) {
41             scanf("%d", &a[i]);
42             m = max(m, a[i]);
43         }
44         LL ret = 0;
45         memset(bit, 0, sizeof(bit));
46         for(int i = 1; i <= n; i++) {
47             add(a[i]);
48             c[i] = sum(a[i]-1);
49         }
50         memset(bit, 0, sizeof(bit));
51         for(int i = n; i >= 1; i--) {
52             add(a[i]);
53             d[i] = sum(a[i]-1);
54         }
55         for(int i = 1; i <= n; i++) {
56             ret += ((i - 1) - c[i]) * d[i] + (n - i - d[i]) * c[i];
57         }
58         cout << ret << endl;
59     }
60     return 0;
61 }

 

posted @ 2017-04-29 19:17  Kirai  阅读(138)  评论(0编辑  收藏  举报