码迷,mamicode.com
首页 > 其他好文 > 详细

[ARC054D]バブルソート

时间:2018-10-27 10:26:52      阅读:189      评论:0      收藏:0      [点我收藏+]

标签:amp   --   merge   printf   复杂度   highlight   cond   define   区间查询   

题意:用如下方法生成一个超长序列:维护一个元素为序列的栈,操作有三种,1.push一个仅含一个数字的序列;2.将栈顶的两个序列合并;3.将栈顶序列重复$k$次后作为新的栈顶,保证操作完后栈中只有一个序列,求这个序列的逆序对数

直接维护整个序列肯定MLE+TLE,考虑只维护一些关键的值,对序列$S$,设$S_x$为序列的逆序对数,$S_y$为$S$对$S$的逆序对数,$S_d$是一个map,存各个元素及其出现次数

$\text{push}(v)$:$S_x=S_y=0,S_d=\{v:1\}$

$\text{repeat}(S,k)$:$S‘_x=kS_x+\binom k2S_y,S_y=k^2S_y$,$S_d$的每个元素出现次数都乘$k$

$\text{merge}(S,T)$:$S‘_x=S_x+T_x+u,S‘_y=S_y+T_y+u+v$,其中$u$为$S$对$T$的逆序对数,$v$为$T$对$S$的逆序对数,最后把$S_d$和$T_d$合并即可

直接暴力做就可以拿$50$分了,因为最慢的地方是合并,考虑优化

用动态开点线段树维护$S_d$,每次合并采用启发式合并的策略:在较小的$S_d$中枚举元素,在$T_d$中区间查询得到$u,v$,再用启发式合并将$S_d,T_d$合并即可(线段树合并也可以,不过不会降低时间复杂度)

全局乘$k$维护一个标记即可

#include<stdio.h>
#include<map>
using namespace std;
typedef long long ll;
const int mod=1000000007,mx=100000;
int mul(int a,int b){return(ll)a*b%mod;}
void inc(int&a,int b){(a+=b)%=mod;}
int pow(int a,int b){
	int s=1;
	while(b){
		if(b&1)s=mul(s,a);
		a=mul(a,a);
		b>>=1;
	}
	return s;
}
struct seg{
	int l,r,s;
}t[20000010];
int M;
void modify(int p,int v,int l,int r,int&x){
	if(x==0)x=++M;
	inc(t[x].s,v);
	if(l==r)return;
	int mid=(l+r)>>1;
	if(p<=mid)
		modify(p,v,l,mid,t[x].l);
	else
		modify(p,v,mid+1,r,t[x].r);
}
int query(int L,int R,int l,int r,int x){
	if(L>R||x==0)return 0;
	if(L<=l&&r<=R)return t[x].s;
	int mid=(l+r)>>1,s=0;
	if(L<=mid)inc(s,query(L,R,l,mid,t[x].l));
	if(mid<R)inc(s,query(L,R,mid+1,r,t[x].r));
	return s;
}
map<int,int>::iterator it;
struct seq{
	int x,y,rt,l;
	map<int,int>s;
	void operator=(int v){
		x=y=0;
		l=1;
		s.clear();
		s[v]=1;
		rt=0;
		modify(v,1,1,mx,rt);
	}
	void operator*=(int k){
		x=(mul(k,x)+mul((ll)k*(k-1)/2%mod,y))%mod;
		y=mul(mul(k,k),y);
		l=mul(l,k);
	}
	void operator+=(seq&b){
		int u,v;
		u=v=0;
		#define id it->first
		#define val it->second
		#define inv(x) pow(x,mod-2)
		if(s.size()>b.s.size()){
			for(it=b.s.begin();it!=b.s.end();it++){
				inc(u,mul(val,query(id+1,mx,1,mx,rt)));
				inc(v,mul(val,query(1,id-1,1,mx,rt)));
			}
			for(it=b.s.begin();it!=b.s.end();it++){
				val=mul(val,mul(b.l,inv(l)));
				modify(id,val,1,mx,rt);
				inc(s[id],val);
			}
		}else{
			for(it=s.begin();it!=s.end();it++){
				inc(u,mul(val,query(1,id-1,1,mx,b.rt)));
				inc(v,mul(val,query(id+1,mx,1,mx,b.rt)));
			}
			for(it=s.begin();it!=s.end();it++){
				val=mul(val,mul(l,inv(b.l)));
				modify(id,val,1,mx,b.rt);
				inc(b.s[id],val);
			}
			s.swap(b.s);
			swap(rt,b.rt);
			swap(l,b.l);
		}
		u=mul(u,mul(l,b.l));
		v=mul(v,mul(l,b.l));
		x=((ll)x+b.x+u)%mod;
		y=((ll)y+b.y+u+v)%mod;
	}
}p[100010];
int main(){
	int n,M,x;
	M=0;
	scanf("%d",&n);
	while(n--){
		scanf("%d",&x);
		if(x>0)p[++M]=x;
		if(x==0){
			M--;
			p[M]+=p[M+1];
		}
		if(x<0)p[M]*=-x;
	}
	for(M--;M;M--)p[M]+=p[M+1];
	printf("%d\n",p[1].x);
}

[ARC054D]バブルソート

标签:amp   --   merge   printf   复杂度   highlight   cond   define   区间查询   

原文地址:https://www.cnblogs.com/jefflyy/p/9859967.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!