题目描述
输入
输出
Data Constraint
输入
输出
输入样例
4
1 4 3 2
输出样例复制
3
.
.
.
.
.
分析
题目中描述(a,b),(c,d)两种二元组的个数很容易用树状数组求出(先离散一下)。
用t1代表(a,b)的个数,t2代表(c,d)的个数,那么t1t2就是(a,b,c,d)的个数,但有点差别,这里的(a,b,c,d)可能会有位置相同的情况。
所以t1t2还要减去一些重复的情况。
有哪些重复情况呢:
很简单:a=c,a=d,b=c,b=d。
分别用树状数组求出四种情况的方案数,从答案中减去就行了。
.
.
.
.
.
程序:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
long long n,s[100005],c[100005],ans,c1[100005],c2[100005];
struct node
{
long long x,id;
}p[100005];
bool cmp(node a,node b)
{
return a.x<b.x;
}
void add(long long x,long long c[])
{
while (x<=n)
{
c[x]++;
x+=x&-x;
}
}
void del(long long x,long long c[])
{
while (x<=n)
{
c[x]--;
x+=x&-x;
}
}
long long ask(long long x,long long c[])
{
long long t=0;
while (x>0)
{
t+=c[x];
x-=x&-x;
}
return t;
}
int main()
{
long long t1=0,t2=0,tot=0;
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%lld",&p[i].x);
p[i].id=i;
}
p[0].x=-2147483647;
sort(p+1,p+n+1,cmp);
for (int i=1;i<=n;i++)
{
if (p[i].x!=p[i-1].x) tot++;
s[p[i].id]=tot;
}
for (int i=1;i<=n;i++)
{
t1+=ask(s[i]-1,c);
add(s[i],c);
}
memset(c,0,sizeof(c));
for (int i=n;i>=1;i--)
{
t2+=ask(s[i]-1,c);
add(s[i],c);
}
ans=t1*t2;
for (int i=1;i<=n;i++)
{
t1=ask(s[i]-1,c1);
t2=ask(tot-s[i],c2);
add(s[i],c1);
add(tot-s[i]+1,c2);
ans-=t1*t2;
}
memset(c1,0,sizeof(c1));
memset(c2,0,sizeof(c2));
for (int i=1;i<=n;i++)
add(s[i],c2);
for (int i=1;i<=n;i++)
{
t1=ask(s[i]-1,c1);
t2=ask(s[i]-1,c2);
add(s[i],c1);
del(s[i],c2);
ans-=t1*t2;
}
memset(c1,0,sizeof(c1));
for (int i=1;i<=n;i++)
{
add(tot-s[i]+1,c1);
add(s[i],c2);
}
for (int i=1;i<=n;i++)
{
t1=ask(tot-s[i],c1);
t2=ask(s[i]-1,c2);
del(tot-s[i]+1,c1);
del(s[i],c2);
ans-=t1*t2;
}
for (int i=1;i<=n;i++)
add(tot-s[i]+1,c1);
for (int i=1;i<=n;i++)
{
t1=ask(tot-s[i],c1);
t2=ask(tot-s[i],c2);
del(tot-s[i]+1,c1);
add(tot-s[i]+1,c2);
ans-=t1*t2;
}
printf("%lld",ans);
return 0;
}