BZOJ 4240 有趣的家庭菜园

第一道树状数组

用到了贪心的想法

交换的代价就是交换完之后的逆序对数

将所有IOI草从高到低放入

贪心判断是放在左边还是放在右边

会爆int

也要考虑有两棵IOI草高度相同

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN=300005;
inline int read(){
	int x=0,f=1,ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int n,data[MAXN];
inline void add(int x,int i){
	while(x<=n) data[x]+=i,x+=x&(-x);
}
inline int query(int x){
	int res=0;
	while(x) res+=data[x],x-=x&(-x);
	return res;
}
int id[MAXN],a[MAXN];
inline int cmp(int x,int y){
	return a[x]>a[y];
}
inline int cal(int x,int num){
	int res=query(x);
	if(res*2>=num) res=num-res;
	// cout<<res<<endl; 
	return res;
}
int main(){
	n=read();
	for(int i=1;i<=n;i++) a[i]=read();
	for(int i=1;i<=n;i++) id[i]=i;
	sort(id+1,id+1+n,cmp);
	long long ans=0;
	for(int i=1;i<=n;i++){
		int k=i;
		while(k<n&&a[id[k]]==a[id[k+1]]) ans+=cal(id[k],i-1),k++;
		ans+=cal(id[k],i-1);
		// cout<<k<<endl;
		// cout<<ans<<endl;
		for(int j=i;j<=k;j++) add(id[j],1);
		i=k;
	}
	printf("%lld\n",ans);
	return 0;
}

  

posted @ 2018-10-08 15:17  古城独钓  阅读(77)  评论(0编辑  收藏  举报