hdu 4000 树状数组

本文介绍了一种使用树状数组解决特定序列问题的方法。通过逆向思维,先计算序列中每个元素后方比其大的元素数量,再找出前方比其小的元素数量,以此统计满足条件的折线总数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在1到n的序列中找满足val[a] < val[c] < val[b],其中(a < b < c)http://acm.hdu.edu.cn/showproblem.php?pid=4000


做题过程:

        我感觉树状数组都是那种先插小的,然后统计一下的那种。这题是求有多少个那样的折线。。。我开始有点蒙。哎,决定多想会,留到明天做。

今天是明天了。

       这题还是个逆向思维,正着弄不出来就逆着弄。


       对于一点x来说,先去找x后面比x大的有bb个(这个可以通过x前面比她小的fs求出来),那么,我们可以求出1,2这两种情况的总和sum。

       然后我们再去找1这样的情况有多少种,从sum里面减去就行了。情况为在x前面比x小的fs,在x后面比x大的bb,这两个数相乘。

/*
Pro: 0

Sol:

date:
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <set>
#include <vector>
#define maxn 100100
#define mod 100000007
using namespace std;
int t,n,c[maxn],val,ca;
__int64 ret,fs,bb;
void modify(int pos, int val){
    while(pos <= n){
        c[pos] += val;
        pos += (pos & -pos);
    }
}
int getsum(int pos){
    int sum = 0;
    while(pos){
        sum += c[pos];
        pos -= (pos & -pos);
    }return sum;
}
void solve(){
    memset(c,0,sizeof(c));
    ret = 0;
    scanf("%d",&n);
    for(int i = 1; i <= n; i ++){
        scanf("%d",&val);
        modify(val,1);
        fs = getsum(val - 1) % mod;//在val前面比val小的
        bb =( ( n - i ) - ( val - 1 - fs ) ) % mod; //在val后面比val大的,后面有多少数,减去比她小的数
        if(bb >= 2)//这个很重要!,因为bb为0的时候就麻烦了。
            ret += ( (bb * (bb - 1) / 2)% mod);
        ret -= (fs * bb % mod);
        ret = (ret % mod + mod) % mod;
    }
    printf("Case #%d: %I64d\n",ca,(ret % mod + mod) % mod);
}
int main(){
    scanf("%d",&t);
    for(ca = 1; ca <= t; ca ++){
        solve();
    }
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值