hdu 5792 World is Exploding(离散化 + 树状数组 + 容斥)

World is Exploding

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 540    Accepted Submission(s): 249


Problem Description
Given a sequence A with length n,count how many quadruple (a,b,c,d) satisfies: abcd,1a<bn,1c<dn,Aa<Ab,Ac>Ad.
 

 

Input
The input consists of multiple test cases. 
Each test case begin with an integer n in a single line.

The next line contains n integers A1,A2An.
1n50000
0Ai1e9
 

 

Output
For each test case,output a line contains an integer.
 

 

Sample Input
4
2 4 1 3
4
1 2 3 4
 

 

Sample Output
1
0
 
 设下标为a、b、c、d的值为A、B、C、D,要求求出A<B且a<b与C<D且c<d的(a, b, c, d)组合有多少种。设RD为右边比当前数大的数的数量,RX是右边比当前数小的数的数量,同理设LX和LD。计数时会重复的种类是AC重合,AD重合,BC重合,BD重合,分别减去RD * RX,RD * LD,LX * RX,LX * LD。RD、RX、LX、LD通过将数组离散化以后用树状数组求,因为可能会有重复元素,所以求RD和LD的方法和白书上的例题略有不同
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ALL(v) (v).begin(), (v).end()
const ll maxn = 50010;
ll A[maxn], C[maxn], n;
ll LX[maxn], RX[maxn], RD[maxn], LD[maxn];

inline ll lowbit(ll x) {
    return x & (-x);
}

ll sum(ll x) {
    ll ret = 0;
    while(x > 0) {
        ret += C[x]; x -= lowbit(x);
    }
    return ret;
}

void add(ll x, ll d) {
    while(x <= maxn) {
        C[x] += d; x += lowbit(x);
    }
}

int main() {
    ll n;
    while(~scanf("%I64d", &n)) {
        vector<ll> v;
        for(ll i = 1; i <= n; i++) {
            scanf("%I64d", &A[i]);
            v.push_back(A[i]);
        }
        sort(ALL(v));
        v.erase(unique(ALL(v)), v.end());
        for(ll i = 1; i <= n; i++) {
            A[i] = lower_bound(ALL(v), A[i]) - v.begin();
            A[i] += 1;
        }
        ll L = 0, R = 0;
        memset(C, 0, sizeof(C));
        for(ll i = 1; i <= n; i++) {
            add(A[i], 1);
            LX[i] = sum(A[i] - 1);
            LD[i] = (i - sum(A[i]));
            L += LX[i];
        }
        memset(C, 0, sizeof(C));
        for(ll i = n; i >= 1; i--) {
            add(A[i], 1);
            RX[i] = sum(A[i] - 1);
            RD[i] = (n - i + 1 - sum(A[i]));
            R += RX[i];
        }
        ll ans = L * R;
        for(ll i = 1; i <= n; i++) {
            ans -= RD[i] * RX[i];
            ans -= RD[i] * LD[i];
            ans -= LX[i] * RX[i];
            ans -= LX[i] * LD[i];
        }
        printf("%I64d\n", ans);
    }
}

 

posted @ 2016-08-03 15:12  MartinEden  阅读(141)  评论(0编辑  收藏  举报