题目链接
题目大意
给定一个序列a[1...n],在一个双端队列中插入序列a中的元素,但只能按元素在a出现的次序插入
问最后双端队列中逆序对数最少是多少
分析
假设前n-1个元素已经插入双端队列,现在要插第n个元素,只需要比较 将它插入最前和最后哪种逆序对增加的较少,就怎样插。
每个元素都是如此
根据局部最优,容易想到贪心的做法
优化
如果不加以优化,我们知道暴力的时间复杂度是O(n^2)的,会超时
由于本题涉及到逆序对,做法——树状数组!(正好能解决,且时间复杂度O(logn)在限制以内
插入每个元素时,只要比较插在左边还是右边使答案增加的较少就行了。
数据范围较大,别忘了离散化一下
#include<bits/stdc++.h> #define ll long long using namespace std; const int N = 200005; int n,t; int c[N],a[N],tem[N]; int lowbit(int x){ return x&-x; } void add(int x,int d){ for(int i=x;i<=n;i+=lowbit(i)){ c[i]+=d; } } ll sum(int x){ ll res=0; for(int i=x;i>0;i-=lowbit(i)){ res+=c[i]; } return res; } int main(){ scanf("%d",&t); while(t--){ memset(c,0,sizeof(c)); ll ans=0; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); tem[i] = a[i]; } sort(tem+1,tem+n+1); for(int i=1;i<=n;i++){ a[i] = lower_bound(tem+1,tem+n+1,a[i])-tem; add(a[i],1); ll l=sum(a[i]-1),r=sum(n)-sum(a[i]); if(l<r) ans+=l; else ans+=r; } printf("%lld\n",ans); } return 0; }Code