求序列中满足Ai < Aj > Ak and i < j < k的组数 树状数组 HIT 2275 Number sequence
来源:互联网 发布:细说php下载 编辑:程序博客网 时间:2024/06/05 03:14
http://acm.hit.edu.cn/hoj/problem/view?id=2275
Number sequence
Submitted : 1632, Accepted : 440
Given a number sequence which has N element(s), please calculate the number of different collocation for three number Ai, Aj, Ak, which satisfy that Ai < Aj > Ak and i < j < k.
InputThe first line is an integer N (N <= 50000). The second line contains N integer(s): A1, A2, ..., An(0 <= Ai <= 32768).
OutputThere is only one number, which is the the number of different collocation.
Sample Input51 2 3 4 1Sample Output
6
解法一
1.正序依次按如下步骤处理每个数据:用树状数组统计之前比它小的有多少,并记录在tmp数组里;从此数据开始向后更新更大的数。对此我要解释一下:树状数组的下标是数的大小,由于是按顺序来的,所以保证了i<j<k。由此可知道前面比此数小的有多少个。
2.将c数组清空后倒叙处理一遍数据。由此可知道后面比此数小的有多少个。
3.将每个数的两个数据相乘求和,最后用long long存储输出。
#include<stdio.h>#include<iostream>#include<string.h>#include<algorithm>#define MAXN 50010#define MAXM 32771 int a[MAXN];int c[MAXM];int tmp[MAXN];int n;int lowbit(int x){ return x&(-x);}void add(int x,int ad){ while(x<MAXM){ c[x]+=ad; x+=lowbit(x); }}int sum(int x){ int res=0; while(x>0){ res+=c[x]; x-=lowbit(x); } return res;}int main(){ while(scanf("%d",&n)!=EOF){ long long ans=0; memset(tmp,0,sizeof(tmp)); memset(c,0,sizeof(c)); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); a[i]++; tmp[i]=sum(a[i]-1); //注意是严格的大于 add(a[i],1); } memset(c,0,sizeof(c)); for(int i=n;i>=1;i--){ ans+=(long long)sum(a[i]-1)*tmp[i]; //(long long)很按理说重要,不过没有加也过了。 add(a[i],1); } printf("%lld\n",ans); } return 0;}
解法二
1 题目要求的是总共的搭配方式,满足Ai < Aj > Ak.并且i j k不同
2 我们开两个树状数组,第一个在输入的时候就去更新。然后我们在去枚举Aj 同时维护第二个树状数组,对于AI来说就是在第二个树状数组里面求和
然后在通过第一个树状数组就可以求出Ak的个数,把结果相乘即可
代码:
#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int MAXN = 50010;int n , num[MAXN];int treeNumOne[MAXN];int treeNumTwo[MAXN];int lowbit(int x){ return x&(-x);}int getSum(int *arr , int x){ int sum = 0; while(x){ sum += arr[x]; x -= lowbit(x); } return sum;}void add(int *arr , int x , int val){ while(x < MAXN){ arr[x] += val; x += lowbit(x); }}long long getAns(){ if(n < 3) return 0; long long ans = 0; add(treeNumTwo , num[1] , 1); for(int i = 2 ; i < n ; i++){ int x = getSum(treeNumTwo , num[i]-1); int y = getSum(treeNumOne , num[i]-1); add(treeNumTwo , num[i] , 1); ans += (x)*(y-x); } return ans;}int main(){ while(scanf("%d" , &n) != EOF){ memset(treeNumOne , 0 , sizeof(treeNumOne)); memset(treeNumTwo , 0 , sizeof(treeNumTwo)); for(int i = 1 ; i <= n ; i++){ scanf("%d" , &num[i]); num[i]++; add(treeNumOne , num[i] , 1); } printf("%lld\n" , getAns()); } return 0;}
- 求序列中满足Ai < Aj > Ak and i < j < k的组数 树状数组 HIT 2275 Number sequence
- 求浮点数数组A={A1,A2,A3,…,An}中,Aj-Ai(j>i)的最大值。要求时间复杂度越小越好
- Codeforces 61E Enemy is weak 求i<j<k && a[i]>a[j]>a[k] 的对数 树状数组
- 给定一个数列a1,a2,a3,...,an和m个三元组表示的查询,对于每个查询(i,j,k),输出ai,ai+1,...,aj的升序排列中第k个数。
- UVa 11078 Ai-Aj(i<j)的最大值
- 给出一列数a1,a2,a3....an,求它们的逆序对数,即有多少个有序对(i,j) 使得i<j,ai>aj,n高达10的6次方
- 三元逆序对 求i<j<k && a[i]>a[j]>a[k] 的对数 树状数组Codeforces 61E Enemy is weak
- 有两个序列A和B,A=(a1,a2,...,ak),B=(b1,b2,...,bk),A和B都按升序排列,对于1<=i,j<=k,求k个最小的(ai+bj),要求算法尽量高效
- 有两个序列A和B,A=(a1,a2,...,ak),B=(b1,b2,...,bk),A和B都按升序排列。对于1<=i,j<=k,求k个最小的(ai+bj)。要求算法尽量高效。
- HIT 2275 Number sequence
- 存在ai * aj = ak
- 找出数组a[]中符合a[i]+a[j]=K的数对
- 给定有序序列 a,b,求出所有a[i]+b[j]中所的第k小的数
- 树状数组 求第K大的数 Swun1012
- 【HDU 5944】【暴力】Fxx and string 【给定一个字符串s,求有多少个三元组(i,j,k)满足i,j,k是等比数列且s[i]=='y'&&s[j]=='r'&&s[k]=='x'】
- 求给定序列的逆序数(树状数组)
- 求一个数组(a(i,j))中元素相减的最大值,且i<=j
- 线段树 树状数组 求大于某个值的第k小的数 hdu 2852 KiKi's K-Number
- Java集合之Stack
- 《Spring揭秘》 第3章 掌控大局的IoC Service Provider 笔记
- MAC Eclipse快捷键
- UDP主要丢包原因及具体问题分析
- Java文件列表显示
- 求序列中满足Ai < Aj > Ak and i < j < k的组数 树状数组 HIT 2275 Number sequence
- swift详解之十四 -----------NSThread 异步下载图片
- 题目:二叉查找树中搜索区间
- HDU 1853--Cyclic Tour【最小费用最大流 && 有向环最小权值覆盖 】
- ZOJ 2104解题报告
- Java集合之Map
- django form关于clean及cleaned_data的说明 以及4种初始化
- 题目:二叉树中的最大路径和
- Android屏幕适配全攻略(最权威的官方适配指导)