首页 > 代码库 > HDU5147 Sequence II(树状数组+前缀和+后缀和)
HDU5147 Sequence II(树状数组+前缀和+后缀和)
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5147
题意:
统计有多少个四元组,满足a[i]<a[j]<a[k]<a[q] i<j<k<p
分析:
要统计四元组的数量我们可以通过枚举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 ,那么这个可以通过用树状数组询问前缀和来实现.
时间复杂度是O(nlogn).具体见代码
代码如下:
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> using namespace std; typedef long long LL; const int maxn = 50010; int t[maxn],n; LL a[maxn]; LL num1[maxn],num2[maxn]; int lowbit(int x){ return x&(-x); } void update(int i,int val) { while(i<=n){ t[i]+=val; i+=lowbit(i); } } LL query(int i) { LL sum=0; while(i>0){ sum+=t[i]; i-=lowbit(i); } return sum; } int main() { int tt; scanf("%d",&tt); while(tt--){ scanf("%d",&n); memset(t,0,sizeof(t)); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); update(a[i],1); num1[i]=query(a[i])-1;//num1[]第i个数之前所有比a[i]小的数的个数 } memset(t,0,sizeof(t)); for(int i=n;i>0;i--){ update(a[i],1); num2[i]=n-i+1-query(a[i]);//num2[]第i个数以后的比a[i]大的数的个数 } LL ans = 0,tmp=0; for(int i=1;i<=n;i++){//i枚举C ans+=tmp*num2[i];//第i-1个数之前小于C-1的数的个数a<b二元组的个数的*num2[]第i个数以后的所有大于C数的个数 tmp=tmp+num1[i];//第i个数之前所有的a<b的二元组的个数 } printf("%I64d\n",ans); } return 0; }
HDU5147 Sequence II(树状数组+前缀和+后缀和)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。