(HDU 5792)World is Exploding <树状数组+去重> 多校训练5
来源:互联网 发布:设计网络营销策划方案 编辑:程序博客网 时间:2024/05/16 11:54
World is Exploding
Problem Description
Given a sequence A with length n,count how many quadruple (a,b,c,d) satisfies: a≠b≠c≠d,1≤a< b≤n,1≤c< d≤n,Aa< Ab,Ac>Ad.
Input
The input consists of multiple test cases.
Each test case begin with an integer n in a single line.
The next line contains n integers A1,A2⋯An.
1≤n≤50000
0≤Ai≤1e9
Output
For each test case,output a line contains an integer.
Sample Input
4
2 4 1 3
4
1 2 3 4
Sample Output
1
0
Author
ZSTU
Source
2016 Multi-University Training Contest 5
题意:
给一组序列,从中找出一个四元组,使四个元素下标两两不同,且a<b,c<d有Xa < Xb , Xc > Xd。问一共有多少组满足要求的四元组。
分析:
对于要求出的结果,我们可以用树状数组很快的求出对于a[i],左边比他小的数的数目ls[i],左边比他大的数的数目lb[i],右边比他小的数的数目rs[i],右边比他大的数的数目rb[i]。
我们可以利用所有的ls[i],lb[i]或者rs[i],rb[i]求出逆序对的个数suml和顺序对的个数sumb。
而 suml * sumb的结果是所有的逆序对和所有的顺序对匹配的结果,而题目要求a,b,c,d互不相等,这里面存在重复的情况:a,c重复,b,d重复,c,b重复,a,d重复(不存在3者或4者重复的情况)
所以我们将结果减去重复的即可:
rs[i]*rb[i]为a,c重合的情况 , ls[i]*lb[i]为b,d重合的情况 , ls[i]*rs[i]为c,b重合的情况 , lb[i]*rb[i]为a,d重合的情况
注意:
在代码中我们用四个数组分别维护了四个值得大小
由于在题目中可能出现两个数相等的情况,而且我们在使用树状数组时要知道每个数(没有重复的情况)的从小到大位置(便于取值和更新)。
所以我们用tmp[]数组存所有的数,并将它排序后去重,然后我们利用lower_bound()函数即可快速求出每个数的位置。
关于更新的处理:例如如下代码
for(int i=0;i<n;i++)//获取ls,lb { a[i] = lower_bound(tmp,tmp+cnt,a[i])-tmp+1;//获取a[i]在数组中从小到大的位置,便于更新 ls[i] = getl(a[i]-1,tls); lb[i] = getr(a[i]+1,tlb); suml += ls[i]; sumb += lb[i]; upr(a[i],tls);//更新 upl(a[i],tlb); }
在计算ls[],lb[]时我们是从左向右插入的,ls[i] = getl(a[i]-1,tls);:获取在a[i]左边(已经插入)的数的数目,对于lb[i] = getr(a[i]+1,tlb);同理
upr(a[i],tls); : 由于a[i]已经插入,所以后面插入的且位置在a[i]后面的值都要更新
upl(a[i],tlb);同理
AC代码
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>using namespace std;typedef long long LL;const int maxn = 50010;int a[maxn],tmp[maxn];int n,cnt;//cnt:去重后的个数int ls[maxn],lb[maxn],rs[maxn],rb[maxn];//s:左边小于当前位的数的个数 , rs:右边小于当前位的数的个数,lb:左边大于当前位的数的个数,rb:右边大于当前位的数的个数int tls[maxn],tlb[maxn],trs[maxn],trb[maxn];//相应的树状数组LL ans,suml,sumb;//答案,逆序对个数,顺序对个数void init(){ memset(tls,0,sizeof(tls)); memset(tlb,0,sizeof(tlb)); memset(trs,0,sizeof(trs)); memset(trb,0,sizeof(trb)); ans = suml = sumb = 0;}LL getl(int x,int *tr)//获取左边的值{ LL res = 0; while(x > 0) { res += (LL)tr[x]; x -= (x&-x); } return res;}LL getr(int x,int *tr)//获取右边的值{ LL res = 0; while(x <= maxn) { res += (LL)tr[x]; x += (x&-x); } return res;}void upl(int x,int *tr)//向左边更新{ while(x > 0) { tr[x] += 1; x -= (x&-x); }}void upr(int x,int *tr)//向右边更新{ while(x <= maxn) { tr[x] += 1; x += (x&-x); }}int main(){ while(scanf("%d",&n)==1) { init(); for(int i=0;i<n;i++) { scanf("%d",&a[i]); tmp[i] = a[i]; } //去重 sort(tmp,tmp+n); cnt = unique(tmp,tmp+n)-tmp; for(int i=0;i<n;i++)//获取ls,lb { a[i] = lower_bound(tmp,tmp+cnt,a[i])-tmp+1;//获取a[i]在数组中从小到大的位置,便于更新 ls[i] = getl(a[i]-1,tls); lb[i] = getr(a[i]+1,tlb); suml += ls[i]; sumb += lb[i]; upr(a[i],tls);//更新 upl(a[i],tlb); } for(int i=n-1;i>=0;i--)//获取rs,rb { rb[i] = getr(a[i]+1,trb); rs[i] = getl(a[i]-1,trs); upr(a[i],trs); upl(a[i],trb); } ans = suml * sumb; for(int i=0;i<n;i++) { ans -= (rs[i]*rb[i] + ls[i]*lb[i] + ls[i]*rs[i] + lb[i]*rb[i]); //rs[i]*rb[i]为a,c重合的情况 , ls[i]*lb[i]为b,d重合的情况 , ls[i]*rs[i]为c,b重合的情况 , lb[i]*rb[i]为a,d重合的情况 } printf("%lld\n",ans); } return 0;}
- (HDU 5792)World is Exploding <树状数组+去重> 多校训练5
- hdu 5792 World is Exploding 树状数组
- HDU-5792-World is Exploding-树状数组
- HDU 5792 World is Exploding (树状数组逆序对)
- HDU-5792-World is Exploding(树状数组+离散化)
- hdu 5792 World is Exploding (树状数组)
- HDU 5792 World is Exploding(树状数组)
- HDU 5792 World is Exploding(树状数组+离散化)
- HDU 5792 多校5 World is Exploding(树状数组,离散化,组合数学)
- hdu 5792 World is Exploding(2016 Multi-University Training Contest 5——树状数组)
- hdu 5792 World is Exploding 离散化+树状数组
- HDU-5792 World is Exploding(思维、树状数组+离散化)
- 2016多校训练Contest5: 1012 World is Exploding hdu5792
- HDU 5792 World is Exploding (容斥原理+离散化+树状数组)
- (one data one problem)hdu-5792 World is Exploding (树状数组)
- (HDU 5792)2016 Multi-University Training Contest 5 World is Exploding (逆序数、顺序数、树状数组)
- HDU 5792 World is Exploding 2016多校赛第五场 树状数组+容斥原理
- HDU 5792 World is Exploding(BIT)
- Java中i++和++i的区别
- C/C++的编译过程
- C/C++中的声明与定义
- C/C++ 中的include
- C++ namespace
- (HDU 5792)World is Exploding <树状数组+去重> 多校训练5
- C/C++的基本数据类型
- VS系列语言包下载提示兼容性或其他问题的解决方法。
- 卷积操作的维度
- Theano conv2d的border_mode
- 线性函数的定义
- 卷积操作的线性性质
- git bash下中文乱码
- iOS-NSURL踩的坑