IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    BZOJ4240: 有趣的家庭菜园

    wyfcyx发表于 2015-08-18 20:32:43
    love 0

    题解:

    首先预处理出$l_i$表示第$i$个数左侧比第$i$个数大的个数,$r_i$右侧同理.

    首先脑补出我们应该将序列排成先单调不降,后单调不增的形式.

    我们从大到小将数插入序列,考虑插入某个数,比这个数大的已经全部插入完毕了,由于排成那种形式,我们只能将这个数放在当前序列的头或尾.

    若放在开头,则带来$l_i$的逆序对;否则带来$r_i$的逆序对.

    显然每个数之间都是独立的,我们直接贪心就行了.

    时间复杂度$O(nlogn)$.

    代码:

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    typedef long long ll;
    
    #define N 300010
    int n,_n,a[N],b[N];
    
    inline int getc(){
    	static const int L=1<<15;
    	static char buf[L],*S=buf,*T=buf;
    	if(S==T){
    		T=(S=buf)+fread(buf,1,L,stdin);
    		if(S==T)
    			return EOF;
    	}
    	return*S++;
    }
    inline int getint(){
    	int c;
    	while(!isdigit(c=getc()));
    	int x=c-'0';
    	while(isdigit(c=getc()))
    		x=(x<<1)+(x<<3)+c-'0';
    	return x;
    }
    
    int A[N],l[N],r[N];
    inline int ask(int x){
    	int re=0;
    	for(;x;x-=x&-x)
    		re+=A[x];
    	return re;
    }
    inline void upd(int x){
    	for(;x<=_n;x+=x&-x)
    		++A[x];
    }
    int main(){
    	n=getint();
    	int i,j;
    	for(i=1;i<=n;++i)
    		a[i]=b[i]=getint();
    	sort(b+1,b+n+1);
    	_n=unique(b+1,b+n+1)-b-1;
    	for(i=1;i<=n;++i)
    		a[i]=lower_bound(b+1,b+_n+1,a[i])-b;
    	for(i=1;i<=n;++i){
    		l[i]=i-1-ask(a[i]);
    		upd(a[i]);
    	}
    	memset(A,0,sizeof A);
    	for(i=n;i>=1;--i){
    		r[i]=n-i-ask(a[i]);
    		upd(a[i]);
    	}
    	long long ans=0;
    	for(i=1;i<=n;++i)
    		ans+=min(l[i],r[i]);
    	cout<<ans<<endl;
    	return 0;
    }


沪ICP备19023445号-2号
友情链接