hdu 4000 Fruit Ninja

/*

题目:
    给出序列,其中一个子序列为(x,y,z),问最多有多少个这样的子序列,
    使得x<z<y,其中该序列为1到n的排列

分析:
    由于是排列,所以不存在相同的元素,所以x,y,z互不相等。所以序列中
    的大小关系可表示为
    小中大+小大中 = 小__ __ ,所以答案 小大中 = 小__ __ -小中大
    统计 小__ __可以统计该位后面的所有元素中比他大的个数为x,则
        小__ __  = x*(x-1)/2
    而统计小中大时,只需要统计前面比他小的以及后面比他大的个数x,y,则
        小中大 = x*y
    统计个数可以用树状数组来统计,树状数组可以统计出前面已加入的元素比
    当前的元素小的个数

*/
#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

#define MOD 100000007
#define X 100005

int a[X];
long long c[X],big[X],sma[X];

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

void modify(int x)
{
    while(x<X)
    {
        c[x] = (c[x]+1)%MOD;
        x += lowbit(x);
    }
}

long long query(int x)
{
    long long ret = 0;
    while(x>0)
    {
        ret += c[x];
        ret %= MOD;
        x -= lowbit(x);
    }
    return ret;
}


int main()
{
    freopen("sum.in","r",stdin);
    freopen("sum.out","w",stdout);
    int cnt = 0,t,n;
    cin>>t;
    while(t--)
    {
        printf("Case #%d: ",++cnt);
        scanf("%d",&n);
        memset(c,0,sizeof(c));
        memset(big,0,sizeof(big));
        memset(sma,0,sizeof(sma));
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            sma[i] = query(a[i]);   ///统计前面比他小的个数
            modify(a[i]);
        }

        memset(c,0,sizeof(c));
        for(int i=n;i>=1;i--)       ///统计后面比他大的个数
        {
            big[i] = n-i-query(a[i]);
            modify(a[i]);
        }
        long long s = 0,b = 0;
        for(int i=1;i<=n;i++)
        {
            s = (s+(big[i]-1)*big[i]/2)%MOD;    ///统计小__ __的个数
            b = (b+big[i]*sma[i])%MOD;          ///统计小中大的个数
        }
        cout<<(s-b+MOD)%MOD<<endl;
    }
    return 0;
}

 

posted @ 2012-06-14 12:08  yejinru  阅读(193)  评论(0编辑  收藏  举报