HDU 4000 Fruit Ninja[树状数组]

题意:问一个1..n 的排列中,有多少组数满足 i < j < k 且 num[i] < num[k] < num[j].

分析:符合条件的答案即为 小大中的情况总数,而

        小大中 = 小XX - 小中大

        可以求出每个数前面小于它的数的个数x,和后面大于它的个数y,

        那么每个数对应的 小XX 数量为 y*(y-1)/2

             每个数对应的 小大中数量为 x*y

   

#include <stdio.h>
#include <string.h>
#define mod 100000007
long long a[100005];
int n;
int lowbit(int x)
{
    return (x)&(-x);
}

void add(int pos)
{
    while (pos <= n)
    {
        a[pos] += 1;
        pos += lowbit(pos);
    }
}

long long sum(int pos)
{
    long long s = 0;
    while (pos > 0)
    {
        s += a[pos];
        pos -= lowbit(pos);
    }
    return s;
}
int main()
{
    int ca = 1;
    int t, i, j;
    int p;
    long long t1, t2, t3, s1, s2;
    scanf("%d",&t);
    while (t--)
    {
        scanf("%d",&n);
        s1 = s2 = 0;

        for(i=0; i<=n; i++)
            a[i] = 0;

        for(i=1; i<=n; i++)
        {
            scanf("%d",&p);
            add(p);
            t1 = sum(p-1);
            t2 = sum(n) - sum(p);
            t3 = n - p - t2;
            s2 += ((t1%mod)*(t3%mod))%mod;
            if (t3%2 == 0)
                s1 += (((t3/2)%mod)*((t3-1)%mod))%mod;
            else
                s1 += ((((t3-1)/2)%mod)*(t3%mod))%mod;

            s1 %= mod;
            s2 %= mod;
        }
        int res = (s1 - s2 + mod)%mod;
        printf("Case #%d: %d\n",ca++,res);
    }
    return 0;
}

 

posted @ 2012-11-02 07:15  'wind  阅读(306)  评论(0编辑  收藏  举报