Sequence II
Time Limit: 5000/2500 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1281 Accepted Submission(s): 523
Total Submission(s): 1281 Accepted Submission(s): 523
Problem Description
Long long ago, there is a sequence A with length n. All numbers in this sequence is no smaller than 1 and no bigger than n, and all numbers are different in this sequence.
Please calculate how many quad (a,b,c,d) satisfy:
1. 1≤a<b<c<d≤n
2. Aa<Ab
3. Ac<Ad
Please calculate how many quad (a,b,c,d) satisfy:
1. 1≤a<b<c<d≤n
2. Aa<Ab
3. Ac<Ad
Input
The first line contains a single integer T, indicating the number of test cases.
Each test case begins with a line contains an integer n.
The next line follows n integers A1,A2,…,An .
[Technical Specification]
1 <= T <= 100
1 <= n <= 50000
1 <= Ai <= n
Each test case begins with a line contains an integer n.
The next line follows n integers A1,A2,…,An .
[Technical Specification]
1 <= T <= 100
1 <= n <= 50000
1 <= Ai <= n
Output
For each case output one line contains a integer,the number of quad.
Sample Input
1 5 1 3 2 4 5
Sample Output
4
首先分析题干:这里的四元组除了位子有相关的大小限制条件之外呢,我们是没有任何相关的关系的,所以我们这里拆分成两个二元组来做。例如样例:
从3开始,13能够组成一组二元组,3之后能够形成3组二元组。
然后是2,1 2能够组成一组二元组,2之后能够形成1组二元组。
然后相乘并且相加1*3+1*1得到结果4.所以呢,我们这里的思维就很好形成了。找到当前数字之前的数字里边比他小的数字和,就是他之前和他能够组成的二元组的组数。
然后再找到这个数之后能够形成的组数。然后相乘就能得到结果。
但是这里,当前数字之后的组数是如何计算的呢?我们这里拿样例来说明。从后向前计算:
5 之后没有数据,能够形成0组二元组。
4之后5比他大,能够形成1组二元组。这里表示数字2之后能够形成1组二元组。
2之后4 5比他大,2 4 2 5能够形成两组二元组 ,加上 4 5的二元组,这里表示数字3之后能够形成3组二元组。
3之后 4 5比他大 3 4 3 5能够形成两组二元组 ,加上 2 4 2 5 4 5三组,这里表示数字1之后能够形成5组二元组。依次类推即可
解题思路:
要统计四元组的数量我们可以通过枚举c,然后统计区间[1,c-1]有多少二元组(a,b)满足a<b且Aa<Ab,以及统计出区间[c+1,n]有多少d满足Ac<Ad,
根据乘法原理,把这两项乘起来就可以统计到答案里了.然后我们来处理子问题:区间[1,c-1]内有多少二元组(a,b).那么我们可以枚举b,然后统计
区间[1,b-1]内有多少a满足Aa<Ab,那么这个可以通过用树状数组询问前缀和来实现.
具体实现:b[i]和c[i]中存储的分别为以i结尾的Ax<Ay的对数和从i+1到n中Ax<Ay的对数,二者相乘即为答案。
时间复杂度是O(nlogn).
要统计四元组的数量我们可以通过枚举c,然后统计区间[1,c-1]有多少二元组(a,b)满足a<b且Aa<Ab,以及统计出区间[c+1,n]有多少d满足Ac<Ad,
根据乘法原理,把这两项乘起来就可以统计到答案里了.然后我们来处理子问题:区间[1,c-1]内有多少二元组(a,b).那么我们可以枚举b,然后统计
区间[1,b-1]内有多少a满足Aa<Ab,那么这个可以通过用树状数组询问前缀和来实现.
具体实现:b[i]和c[i]中存储的分别为以i结尾的Ax<Ay的对数和从i+1到n中Ax<Ay的对数,二者相乘即为答案。
时间复杂度是O(nlogn).
#include<bits/stdc++.h>
#include <ctime>
using namespace std;
typedef long long ll;
int n;
int tree[55000];
int b[55000], c[55000], a[55000];
int lowbit(int x)
{
return x & (-x);
}
int sum(int x)
{
int sum = 0;
while (x > 0)
{
sum += tree[x];
x -= lowbit(x);
}
return sum;
}
void add(int x, int c)
{
while (x <= n)
{
tree[x] += c;
x += lowbit(x);
}
}
int main()
{
std::ios::sync_with_stdio(false);
int t;
cin >> t;
while (t--)
{
memset(b, 0, sizeof(b));
memset(c, 0, sizeof(c));
memset(a, 0, sizeof(a));
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
memset(tree, 0, sizeof(tree));
for (int i = 1; i <= n; i++)
{
b[i] = sum(a[i]);
add(a[i], 1);
}
memset(tree, 0, sizeof(tree));
for (int i = n; i >= 1; i--)
{
c[i] = sum(n) - sum(a[i]) + c[i + 1];
add(a[i], 1);
}
ll ans = 0;
for (int i = 2; i <= n - 2; i++)
{
ll x = b[i];
ll y = c[i + 1];
ans += x * y;
}
cout << ans << endl;
}
}