在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;
}