题意:多组输入,每组数据第一行n,代表数列中元素个数,接下来n个数。从这n个数中找出满足下列条件的a,b,c,d四个数
求满足条件的个数。
思路分析:题目 就是让找一对逆序,与一对顺序,并且两对数不能有重复的元素。重复是指位置重复,并不是值一样。找出全部的逆序数,顺序数两个 数相乘再进行去重就得到答案
代码实现:用树状数组来统计第i个位置左边小于它的个数,左边大于他的个数。再逆序建立树状数组,找出第i个位置右面大于它的个数,右面小于它的个数。在建立树状数组之前要注意进行离散化,我的离散化感觉有点麻烦,用结构体来存的元素val代表原来的值,pre代表最初的顺序,now代表离散化后的数。离散化的数值是从2开始的,因为之后树状数组查询的是查询i-1排除重复的元素,避开i-1值为0。
队友的离散化感觉挺简单的:
for(int i=0; i < n ; i++){
scanf("%I64d",&num[i]);
tmp[i]=num[i];
}
sort(tmp,tmp+n);
ll size=unique(tmp,tmp+n)-tmp ;
for(int i=0; i < n ; i++){
num[i]=lower_bound(tmp,tmp+size,num[i]) - tmp + 1;
}
AC代码(为了方便全部定义为了long long):
#include <iostream>
#include <cmath>
#include <stdio.h>
#include <algorithm>
#include <cstring>
#include <map>
using namespace std;
typedef long long ll;
typedef long long LL;
#define maxn 50050
struct NUM
{
ll pre;///读入的元素
ll now;///离散后的数
ll val;///输入的值
}num[maxn];
bool cmp1(NUM a,NUM b)
{
if(a.val==b.val)
return a.pre<b.pre;
return a.val<b.val;
}
bool cmp(NUM a,NUM b)
{
return a.pre<b.pre;
}
ll a[maxn];
ll c[maxn],n;///c[]存储树状数组
ll lowbit(ll x)
{
return x&(-x);
}
void update(ll i,ll x)
{
while(i<=n) {c[i]=c[i]+x; i+=lowbit(i);}
}
ll query(ll i)
{
ll ans=0;
while(i>0) {ans+=c[i]; i-=lowbit(i);}
return ans;
}
struct type///记录每个数的左右比他大的和小的个数
{
ll lbig,llow,rbig,rlow;
}numflag[maxn];
int main()
{
ll N;
while(~scanf("%I64d",&N))
{
for(ll i=1;i<=N;i++)
{
scanf("%I64d",&num[i].val);
num[i].pre=i;
}
sort(num+1,num+1+N,cmp1);
num[1].now=2;
n=2;
for(ll i=2;i<=N;i++)
{
if(num[i].val!=num[i-1].val)
n++;
num[i].now=n;
}
sort(num+1,num+1+N,cmp);
memset(c,0,sizeof(c));
for(ll i=1;i<=N;i++)
{
update(num[i].now,1);
numflag[i].llow=query(num[i].now-1);
numflag[i].lbig=i-query(num[i].now);
}
memset(c,0,sizeof(c));///逆序建立新的树状数组
for(int i=N;i>=1;i--)
{
update(num[i].now,1);
numflag[i].rlow=query(num[i].now-1);
numflag[i].rbig=N-i+1-query(num[i].now);
}
ll suml=0,sumr=0;///suml顺序对的个数,sumr逆序对的个数
for(int i=1;i<=N;i++)
{
suml+=numflag[i].lbig;
sumr+=numflag[i].rbig;
}
ll ans=suml*sumr;
for(int i=1;i<=N;i++)///除重操作
{
ans-=numflag[i].llow*numflag[i].lbig;
ans-=numflag[i].llow*numflag[i].rlow;
ans-=numflag[i].rbig*numflag[i].rlow;
ans-=numflag[i].lbig*numflag[i].rbig;
}
printf("%I64d\n",ans);
}
return 0;
}