【DBSDFZOJ 4409】a(离散化+树状数组)
2017-09-18 10:13
337 查看
Description
逆序对是一个非常经典的问题,但是逆序对虽然经典,但却是一个非常困难的问题,因为一个序列的逆序对数可能太多了。所以为了简化问题,我们给定一个长度为N的序列z和一个参数k,我们希望知道有多少个(L,R)满足1 <= L < R <= N,且z1, z2, ⋯ , zL, zR, ⋯ , zN的逆序对个数不超过k。Input
第一行两个整数N, k。接下来一行N个整数代表序列。
Output
一行一个整数代表答案。Sample Input 1
3 11 3 2
Sample Output 1
3Sample Input 2
5 21 3 2 1 7
Sample Output 2
6Data Constraint
对于100%的数据,1 <= N <= 10^5, 1 <= zi <= 10^9, k <= 10^18,有部分分。解题思路
先离散化zi的值,用一个树状数组记录一个数前面比它大的数的个数,另一个树状数组记录一个数后面比它小的数的个数。从1至n-1枚举每一个L,R从2开始,对于每一个L,R向右找到当时逆序对数不超过k的最小值,此时的R~n都可以是可行的R的方案,加入到答案里。显然R是递增的。代码
#include<bits/stdc++.h> #define lowbit(x) (x&(-x)) #define N 100001 #define LL long long using namespace std; int n,b[N+5],a[N+5],tree[2][N+5]; LL k,now=0,ans=0; inline void add(int x,int num,int opt){ while(x<=N){ tree[opt][x]+=num; x+=lowbit(x); } } inline int search(int x,int opt){ int re=0; while(x){ re+=tree[opt][x]; x-=lowbit(x); } return re; } int main(){ scanf("%d%lld",&n,&k); for(int i=1;i<=n;++i) scanf("%d",&a[i]),b[i]=a[i]; sort(b+1,b+n+1);unique(b+1,b+n+1); for(int i=1;i<=n;++i) a[i]=lower_bound(b+1,b+n+1,a[i])-b; for(int i=n;i>=2;--i){ now+=search(a[i]-1,1); add(a[i],1,1); } LL R=2; for(int i=1;i<=n-1;++i){ now+=search(N-a[i]-1,0)+search(a[i]-1,1); add(N-a[i],1,0); while((now>k || R<=i) && R<=n){ now-=search(N-a[R]-1,0)+search(a[R]-1,1); add(a[R],-1,1); ++R; } if(R==n+1) break; ans+=n-R+1; } printf("%lld",ans); return 0; }
相关文章推荐
- 【DBSDFZOJ 4845】三元组(树状数组)
- ZOJ-3612-树状数组+第k小数+离散化
- 【DBSDFZOJ 4370】小宁的机器人(模拟)
- 【DBSDFZOJ 4844】区间(分治)
- 【DBSDFZOJ 4445】棋盘(组合数学-错排公式+高精度)
- 【DBSDFZOJ 4415】黄金拼图(乱搞)
- 【DBSDFZOJ 4846】攻略(贪心)
- [DBSDFZOJ 多校联训] Password
- 【乱搞】【DBSDFZOJ 4415】黄金拼图
- 【DBSDFZOJ 4847】环线(矩阵快速幂)
- [DBSDFZOJ 多校联训] 就
- 【DBSDFZOJ 4448】a(乱搞)
- 【转】【DBSDFZOJ 1163】分治 第K小元素(分治)
- 【DBSDFZOJ 4430】陶陶摘苹果(DP)
- 【模板】进制转换【DBSDFZOJ】
- 【DBSDFZOJ 4460】666(DP)
- UVA-10810 Ultra-QuickSort 树状数组+离散化 / 归并排序
- poj 2299 Ultra-QuickSort(归并排序)||(树状数组+离散化)
- Foj 2236 第十四个目标 (树状数组+简单dp+离散化)
- 树状数组 --- (离散化+树状数组、求逆序对)