HDU4000 Fruit Ninja(树状数组)

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3426    Accepted Submission(s): 1035


 

Problem Description

Recently, dobby is addicted in the Fruit Ninja. As you know, dobby is a free elf, so unlike other elves, he could do whatever he wants.But the hands of the elves are somehow strange, so when he cuts the fruit, he can only make specific move of his hands. Moreover, he can only start his hand in point A, and then move to point B,then move to point C,and he must make sure that point A is the lowest, point B is the highest, and point C is in the middle. Another elf, Kreacher, is not interested in cutting fruits, but he is very interested in numbers.Now, he wonders, give you a permutation of 1 to N, how many triples that makes such a relationship can you find ? That is , how many (x,y,z) can you find such that x < z < y ?

 

Input

The first line contains a positive integer T(T <= 10), indicates the number of test cases.For each test case, the first line of input is a positive integer N(N <= 100,000), and the second line is a permutation of 1 to N.

 

Output

For each test case, ouput the number of triples as the sample below, you just need to output the result mod 100000007.

 

Sample Input

 

2 6 1 3 2 6 5 4 5 3 5 2 4 1

 

Sample Output

 

Case #1: 10

Case #2: 1

PS:这是参考大佬博客上的题解,讲的很清楚,大家可以参考下。

给出n个数,求所有的i<j<k且a[i]<a[k]<a[j]的个数

题目也就是让最后那个数第二大。我们输入第i个数字a,那么我们用的树状数组存的就是sum(a-1),sum(a-1)表示在a这个位置,在前i-1个数中,有sum(a-1)个数比a小,那么我们就可以求出在后面的(i+1,n)的序列中,有R=(n-a)-(i-1-sum(a-1))个数比a要大,(n-a)表示有这么多个数比a大,(i-1-sum(a-1))表示前i-1个数里面有sum(a-1)个数比a大,那么R=(n-a)-(i-1-sum(a-1))就表示后面有多少个数比a要大。然后,我们思考一下,a当作三个数里面的最小值,然后让它们组合,是不是就是有C(R,2)即R*(R-1)/2,因为后面的序列都是固定的,所以并没有排序的概念,也就是说,原本序列1 5 4 ,那么我们没有必要去思考1 4 5的情况,因为它已经固定好了,所以后面的序列选的时候直接从R个选2个就可以了,然后C(R,2)表示所有的a+两个大的(也就是小中大,小大中都包含在里面了),那么我们要求的是小大中,所以对于每一个a来说,我们都需要减去小中大的情况,那么小中大=sum(a-1)*R,所以最后答案就是对于(1,n)所有数,求和SUM(C(R,2)-sum(a-1)*R。

AC代码:

#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<string>
#include<map>
#include<cmath>
#include<vector>
const int maxn=5e5+5;
const int mod=1e8+7;
#define me(a,b) memset(a,b,sizeof(a))
typedef long long ll;
using namespace std;
int n,bit[maxn];
int lowbit(int x)
{
    return x&(-x);
}
void updata(int x)
{
    while(x<=n)
    {
        bit[x]++;
        x+=lowbit(x);
    }
}
int getsum(int x)
{
    int s=0;
    while(x)
    {
        s+=bit[x];
        x-=lowbit(x);
    }
    return s;
}
int main()
{
    int t,Case=0;cin>>t;
    while(t--)
    {
        me(bit,0);
        scanf("%d",&n);
        ll sum=0,x,l,r;///l,前面输入比x小的数的个数,r表示输入数中比x大的数的个数。
        for(int i=0;i<n;i++)
        {
            scanf("%lld",&x);
            updata(x);
            l=getsum(x-1);
            r=(n-x)-(i-l-1);///(n-x)表示有这么多个数比x大,(i-1-l)表示前i-1个数里面有sum(x-1)个数比a大
            sum+=r*(r-1)/2-r*l;
        }
        printf("Case #%d: %lld\n",++Case,sum%mod);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41292370/article/details/81292376