HDU 4000 Fruit Ninja

参看资料:

https://blog.csdn.net/keepcoral/article/details/80550168


题目:

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

题目大意:

        给定 N 个数的数组A,问能够找到多少(x,y,z),使得 x< y< z,且 A[ x ]<A[ z ]<A[ y ]  。

解题思路:

        要以整体【整个数组】的思想来看这道题,就会明白这个人到底在做什么。

        当我们输入第 i 个数字 a 时,用的树状数组存储 sum(a-1) 【sum(a-1) 表示:在a这个位置的前 i-1 个数中,有sum(a-1)个数比 a 小】。

        那么,就可以求出在 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大】。

       然后,让a当作三个数里面的最小值,以此取出三个数的组合,就有 C(R,2) 即 R*(R-1)/2 ,因为后面的序列都是固定的,所以并没有排序的概念。【例:原本序列1 5 4 ,那么我们没有必要去思考1 4 5的情况,因为它已经固定好了(一开始死都想不通....)】。

       所以后面的序列选的时候直接从R个选2个就可以了,然后C(R,2)表示所有的a与两个大于 a 的数的组合【也就是小中大,小大中都包含在里面了】。那么我们要求的是小大中,所以对于每一个a来说,我们都需要减去 “小中大” 的情况,那么小中大=sum(a-1)*R,所以最后答案就是对于(1,n)所有数,求和SUM(C(R,2)-sum(a-1)*R)

 

实现代码:

#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
int n;
ll c[100009];
ll lowbit(ll x){
    return x&(-x);
}
ll getsum(ll x){
    ll sum=0;
    while(x){
        sum+=c[x];
        x-=lowbit(x);
    }
    return sum;
}
void update(ll x,ll val){
    while(x<=n){
        c[x]+=val;
        x+=lowbit(x);
    }
}
int main(){
    int i,T;
    scanf("%d",&T);
    int Count=1;
    while(T--){
        ll ans=0;
        scanf("%d",&n);
        memset(c,0,sizeof(c));
        for(i=1; i<=n; i++){
            ll a,L,R;
            scanf("%lld",&a);
            update(a,1);
            L=getsum(a-1);  //Left表示有多少个数比a小,
            R=(n-a)-(i-1-L);//前面n-a的含义是有多少个数比a大
            //(i-1-Left)表示i-1个数里面有这么多个数比a大
            ans+=R*(R-1)/2-L*R;
        }
        printf("Case #%d: %lld\n",Count++,ans%100000007);
    }
}

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值