链接
题意
给出一个1到n的全排列,问有多少个四元组(a, b, c, d)满足a < b < c < d,且q[a] < q[b]、q[c] < q[d]。
题解
对每个位置记录其前方比它大的有多少个left[],其后方比它大的有多少个right[],这个利用树状数组逐个插入元素很容易做到。
直接枚举的话复杂度就还是O(n^2),需要记录left的前缀和sum,然后枚举right[i] * sum[i-1]就可以了。
代码
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long lint;
#define maxn (50010)
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
int seg[maxn], a[maxn];
inline int lowbit(int x)
{ return x&-x; }
void add(int x, int val, int n)
{
for(int i = x; i <= n; i += lowbit(i))
{
seg[i] += val;
}
}
int get(int x)
{
int sum = 0;
for(int i = x; i; i -= lowbit(i))
sum += seg[i];
return sum;
}
#define left lleft
#define right rright
lint left[maxn], right[maxn];
int main()
{
int T;
cin >> T;
while(T--)
{
int n;
cin >> n;
memset(seg, 0, sizeof(int)*(n+1));
for(int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
left[i] = get(a[i] - 1);
add(a[i], 1, n);
}
memset(seg, 0, sizeof(int)*(n+1));
for(int i = n; i >= 1; i--)
{
right[i] = get(n) - get(a[i]);
add(a[i], 1, n);
}
for(int i = 2; i <= n; i++)
left[i] += left[i-1];
lint o = 0;
for(int i = 2; i <= n-1; i++)
o += left[i-1] * right[i];
cout << o << endl;
}
return 0;
}