题意:给定一个排列,其中有可能有一些未确定的数,求出所有可能的排列的排名之和
首先我们要知道怎么算一个给定排列的排名,设它为$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)$
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)); }