[CODE FESTIVAL 2016 qual C E]Encyclopedia of Permutations

题意:给定一个排列,其中有可能有一些未确定的数,求出所有可能的排列的排名之和

首先我们要知道怎么算一个给定排列的排名,设它为$p_{1\cdots n}$

排名即为比它小的排列数$+1$,对于每一个比$p$小的排列$s$,我们都能找到$i$使得对于$j\lt i$有$p_j=s_j$且$p_i\gt s_i$,枚举这个$i$,$s_i$可以是任何$\lt p_i$且不在$p_{1\cdots i-1}$中的数,有$p_i-1-\sum\limits_{j\lt i}[p_j\lt p_i]$种选择,后面的$n-i$个数可以用$p_{i+1\cdots n}$随意重排得到,于是$p$的排名为$1+\sum\limits_{i=1}^n(n-i)!\left(p_i-1-\sum\limits_{j\lt i}[p_j\lt p_i]\right)$(所以求一个排列的排名可以用树状数组做到$O(n\log n)$)

现在来做这道题,枚举每一个可能的排列$s$计算答案,为了方便,以下的下标和排列都是$0\cdots n-1$,设$p$中有$k$位未确定,则有$k!$个不同的$s$

$\begin{aligned}&\quad\sum\limits_s1+\sum\limits_{i=0}^{n-1}(n-1-i)!\left(s_i-\sum\limits_{j\lt i}[s_j\lt s_i]\right)\\&=k!+\sum\limits_{i=0}^{n-1}(n-1-i)\sum\limits_s\left(s_i-\sum\limits_{j\lt i}[s_j\lt s_i]\right)\end{aligned}$

前面的部分和$\sum\limits_ss_i$都是很好算的,现在我们要算$\sum\limits_{j\lt i}\sum\limits_s[s_j\lt s_i]$,分类讨论一下

1.$p_i\neq0$,$\sum\limits_ss_i=k!p_i$

1-1.$p_j\neq0$,答案为$k!\sum\limits_{j\lt i}[p_j\lt p_i,p_j\neq 0]$,用树状数组算即可

1-2.$p_j=0$,$s_j$可以从$x\notin p,x\lt p_i$中的数任选,预处理$s_i=\sum\limits_{j\leq i}[p_i=0],np_i=\sum\limits_{j\leq i}[j\notin p]$,答案即为$(k-1)!np_{p_i}\cdot s_i$

2.$p_i=0$,$\sum\limits_ss_i=(k-1)!\sum\limits_{i\notin p}i$

2-1.$p_j\neq0$,$s_i$可以从$x\notin p,x\gt p_j$中的数任选,预处理$sn_i=\sum\limits_{j\leq i}[p_j\neq0]np_{p_j}$,答案为$(k-1)!((i-s_{i-1})np_n-sn_i)$

扫描二维码关注公众号,回复: 3429841 查看本文章

2-2.$p_j=0$,$s_i,s_j$在满足$s_j\lt s_i$的条件下任选,所以答案为$(s_i-1)\binom k2(k-2)!$

总时间复杂度$O(n\log n)$

#include<stdio.h>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mod=1000000007;
int mul(int a,int b){return(ll)a*b%mod;}
int ad(int a,int b){return(a+b)%mod;}
void inc(int&a,int b){(a+=b)%=mod;}
int p[500010],rp[500010],s[500010],fac[500010],np[500010],l[500010],sn[500010];
//s[i] = '-1's in 0...i
//np[i] = count x [x<=i,x not in p]
//l[i] = count j [j<i,pj<pi,pj!=-1]
//sn[i]= sum [j<=i,pj!=-1] np[pj]
int tr[500010],n;
int lowbit(int x){return x&-x;}
void modify(int x){
	while(x<=n){
		tr[x]++;
		x+=lowbit(x);
	}
}
int query(int x){
	int s=0;
	while(x){
		s+=tr[x];
		x-=lowbit(x);
	}
	return s;
}
int C2(ll n){return n*(n-1)/2%mod;}
int main(){
	int k,i,ans,tmp,snp;
	scanf("%d",&n);
	k=0;
	for(i=0;i<n;i++){
		np[i]=1;
		rp[i]=l[i]=-1;
	}
	for(i=0;i<n;i++){
		scanf("%d",p+i);
		p[i]--;
		if(p[i]==-1)
			k++;
		else{
			np[p[i]]=0;
			rp[p[i]]=i;
		}
		s[i]=k;
	}
	for(i=0;i<n;i++){
		if(~rp[i]){
			l[rp[i]]=query(rp[i]+1);
			modify(rp[i]+1);
		}
	}
	l[0]=0;
	for(i=1;i<n;i++){
		if(l[i]==-1)l[i]=l[i-1];
	}
	snp=0;
	for(i=0;i<n;i++){
		if(np[i])inc(snp,i);
	}
	for(i=1;i<=n;i++)np[i]+=np[i-1];
	fac[0]=1;
	for(i=1;i<=n;i++)fac[i]=mul(fac[i-1],i);
	for(i=0;i<n;i++){
		if(i)sn[i]=sn[i-1];
		if(~p[i])inc(sn[i],np[p[i]]);
	}
	ans=0;
	for(i=0;i<n;i++){
		if(~p[i]){
			tmp=mul(fac[k],l[i]);
			if(k)inc(tmp,mul(mul(np[p[i]],fac[k-1]),s[i]));
			inc(ans,mul(fac[n-1-i],mul(fac[k],p[i])-tmp));
		}else{
			if(i)
				tmp=mul(fac[k-1],mul(i-s[i-1],np[n])-sn[i]);
			else
				tmp=0;
			if(s[i]>1)inc(tmp,mul(s[i]-1,mul(C2(k),fac[k-2])));
			inc(ans,mul(fac[n-1-i],mul(snp,fac[k-1])-tmp));
		}
	}
	inc(ans,fac[k]);
	printf("%d",ad(ans,mod));
}

猜你喜欢

转载自www.cnblogs.com/jefflyy/p/9745946.html