HDU5147 Sequence II(樹狀陣列+字首和+字尾和)

bigbigship發表於2014-12-21

題目連結:

http://acm.hdu.edu.cn/showproblem.php?pid=5147


題意:

統計有多少個四元組,滿足a[i]<a[j]<a[k]<a[q] i<j<k<p


分析:   

要統計四元組的數量我們可以通過列舉c,然後統計區間[1,c-1]有多少二元組(a,b)滿足a<b且Aa<Ab,以及統計出區間
[c+1,n]有多少d滿足Ac<Ad,根據乘法原理,把這兩項乘起來就可以統計到答案裡了.

然後我們來處理子問題:區間[1,c-1]內有多少二元組(a,b).那麼我們可以列舉b,然後統計區間[1,b-1]內有多少a滿足



Aa<Ab,那麼這個可以通過用樹狀陣列詢問字首和來實現.

時間複雜度是O(nlogn).具體見程式碼
程式碼如下:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>

using namespace std;

typedef long long LL;
const int maxn = 50010;

int t[maxn],n;

LL a[maxn];
LL num1[maxn],num2[maxn];

int lowbit(int x){
    return x&(-x);
}

void update(int i,int val)
{
    while(i<=n){
        t[i]+=val;
        i+=lowbit(i);
    }
}

LL query(int i)
{
    LL sum=0;
    while(i>0){
        sum+=t[i];
        i-=lowbit(i);
    }
    return sum;
}

int main()
{
    int tt;
    scanf("%d",&tt);
    while(tt--){
        scanf("%d",&n);
        memset(t,0,sizeof(t));
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            update(a[i],1);
            num1[i]=query(a[i])-1;//num1[]第i個數之前所有比a[i]小的數的個數
        }
        memset(t,0,sizeof(t));
        for(int i=n;i>0;i--){
            update(a[i],1);
            num2[i]=n-i+1-query(a[i]);//num2[]第i個數以後的比a[i]大的數的個數
        }
        LL ans = 0,tmp=0;
        for(int i=1;i<=n;i++){//i列舉C
            ans+=tmp*num2[i];//第i-1個數之前小於C-1的數的個數a<b二元組的個數的*num2[]第i個數以後的所有大於C數的個數
            tmp=tmp+num1[i];//第i個數之前所有的a<b的二元組的個數
        }
        printf("%I64d\n",ans);
    }
    return 0;
}


相關文章