Sequence II
Time Limit: 5000/2500 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 962 Accepted Submission(s): 386
Please calculate how many quad (a,b,c,d) satisfy:
1. 1≤a<b<c<d≤n
2. A
3. A
Each test case begins with a line contains an integer n.
The next line follows n integers A
[Technical Specification]
1 <= T <= 100
1 <= n <= 50000
1 <= A
1 5 1 3 2 4 5
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组二元组。依次类推即可。
然后我们这里初始化为:
int b[100005];//表示当前数字前边能够组成的二元组数。
int c[100005];//表示当前数字之后能够形成的二元组数。
int a[100005];//元素。
那么我们如何确定大小关系呢?
我们这里应用树状数组来解决。
这里先贴上树状数组相关的三个函数:
int tree[100005];//树
int lowbit(int x)//lowbit
{
return x&(-x);
}
int sum(int x)//求和求的是比当前数小的数字之和,至于这里如何实现,很简单:int sum=sum(a[i]);
{
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);
}
}
这里我们能够通过sum(a[i])来求得有多少个数比a【i】小,能够通过sum(n)-sum(a[i])来求得有多少个数比a【i】 大。然后我们就能很容易求出b【】和c【】:
memset(tree,0,sizeof(tree));
for(int i=1;i<=n;i++)
{
b[i]=sum(a[i]);//a[i]之前,比a[i]小的数的个数
add(a[i],1);
}
memset(tree,0,sizeof(tree));//注意这里要memset一下。
for(int i=n;i>=1;i--)
{
c[i]=sum(n)-sum(a[i])+c[i+1];//a[i]之后,能形成二元组的组数.
add(a[i],1);
}
然后上完整的AC代码:
#include<stdio.h>
#include<string.h>
using namespace std;
int tree[100005];
int b[100005];
int c[100005];
int a[100005];
int n;
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()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
memset(tree,0,sizeof(tree));
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
memset(tree,0,sizeof(tree));
for(int i=1;i<=n;i++)
{
b[i]=sum(a[i]);//a[i]之前,比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];//a[i]之后,能形成二元组的组数.
add(a[i],1);
}
long long output=0;
for(int i=2;i<=n-2;i++)
{
long long x=b[i];
long long y=c[i+1];
output+=x*y;
}
printf("%I64d\n",output);
}
}