题意:
给一个盒子,里面装着
n
个球,每个球有个权值,现要从盒子里拿出两个球,求第一个球的权值大于第二个球的权值的概率。共
思路:
首先,很容易想出总的情况的个数为
n∗(n−1)
,那么我们只需找出满足要求的情况个数即可。
暴力解法:二重循环直接枚举出所有
ai>aj
的种类数,最后除以
n∗(n−1)
,完事。复杂度为
O(n2)
。
有意思的解法:我们的核心任务是求出
ai>aj
的种类数,那么我们可以借助下树状数组这种科技,我们可以在
O(logn)
的时间内在
ai
这个位置插入一个1,表示下这个位置有个数,然后在所有的数都处理完之后在对每个
ai
找一下它前面有多少个数,这个操作也是
O(logn)
的,那么总的复杂度自然为
O(nlogn)
了。
上个代码:
#include <cstdio>
#include <cstring>
const int MAXN = 400;
int a[MAXN], c[MAXN];
inline int lowbit(int x){
return x & -x;
}
void add(int pos, int p){
for(int i = pos; i < MAXN; i += lowbit(i)){
c[i] += p;
}
return;
}
int query(int pos){
int sum = 0;
while(pos){
sum += c[pos];
pos -= lowbit(pos);
}
return sum;
}
int main(int argc, char const *argv[]){
int cas;
scanf("%d", &cas);
while(cas--){
int n;
scanf("%d", &n);
memset(c, 0, sizeof(c));
for(int i = 0; i < n; i++){
scanf("%d", a + i);
add(a[i], 1);
}
int sum = 0;
for(int i = 0; i < n; i++){
sum += query(a[i] - 1);
}
printf("%.6f\n", sum * 1.0 / ( (n - 1) * n) );
}
return 0;
}