[ARC054D]バブルソート

Posted jefflyy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[ARC054D]バブルソート相关的知识,希望对你有一定的参考价值。

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

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

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

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

$ ext{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
",p[1].x);
}

以上是关于[ARC054D]バブルソート的主要内容,如果未能解决你的问题,请参考以下文章

java 入力値をいくつか持ち,「结束」と入力されたら升顺で并び替えて(バブルソート)表示する。

php サブループとページナビ

sql スキーマのテーブル名を取得

テーブルコントロールTable Controls: スクロールを伴う場合の例

sql MySQL的でテーブルをまるっとコピー

markdown Dockerfileチートシート