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

首先我们要知道怎么算一个给定排列的排名,设它为$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));
}

[CODE FESTIVAL 2016]Encyclopedia of Permutations的更多相关文章

  1. 【AtCoder】CODE FESTIVAL 2016 qual C

    CODE FESTIVAL 2016 qual C A - CF -- #include <bits/stdc++.h> #define fi first #define se secon ...

  2. 【AtCoder】CODE FESTIVAL 2016 qual A

    CODE FESTIVAL 2016 qual A A - CODEFESTIVAL 2016 -- #include <bits/stdc++.h> #define fi first # ...

  3. 【AtCoder】CODE FESTIVAL 2016 qual B

    CODE FESTIVAL 2016 qual B A - Signboard -- #include <bits/stdc++.h> #define fi first #define s ...

  4. Atcoder CODE FESTIVAL 2016 Grand Final E - Water Distribution

    Atcoder CODE FESTIVAL 2016 Grand Final E - Water Distribution 题目链接:https://atcoder.jp/contests/cf16- ...

  5. Atcoder CODE FESTIVAL 2016 qual C 的E题 Encyclopedia of Permutations

    题意: 对于一个长度为n的排列P,如果P在所有长度为n的排列中,按照字典序排列后,在第s位,则P的value为s 现在给出一个长度为n的排列P,P有一些位置确定了,另外一些位置为0,表示不确定. 现在 ...

  6. CODE FESTIVAL 2016 qualA Grid and Integers

    划年代久远的水 题意 有一个R*C的棋盘,要求在每个格子上填一个非负数,使得对任意一个2*2的正方形区域,左上角和右下角的数字之和等于左下角和右上角的数字之和.有一些格子已经被填上了数字,问现在能否满 ...

  7. [CODE FESTIVAL 2016]Problem on Tree

    题意:给一棵树,对于一个满足以下要求的序列$v_{1\cdots m}$,求最大的$m$ 对$\forall1\leq i\lt m$,路径$(v_i,v_{i+1})$不包含$v$中除了$v_i,v ...

  8. [CODE FESTIVAL 2016]Distance Pairs

    题意:有一个未知的边权为$1$的图,给定所有点到$1$的最短路$a_i$和到$2$的最短路$b_i$,问是否存在这样的图,如果存在,问图中最少有多少条边 先考虑$a_i$,有$a_1=0,a_i\ne ...

  9. CODE FESTIVAL 2016 Grand Final 题解

    传送门 越学觉得自己越蠢--这场除了\(A\)之外一道都不会-- \(A\) 贪心从左往右扫,能匹配就匹配就好了 //quming #include<bits/stdc++.h> #def ...

随机推荐

  1. Different Integers(牛客多校第一场+莫队做法)

    题目链接:https://www.nowcoder.com/acm/contest/139/J 题目: 题意:给你n个数,q次查询,对于每次查询得l,r,求1~l和r~n元素得种类. 莫队思路:1.将 ...

  2. python进行机器学习(二)之特征选择

    毫无疑问,解决一个问题最重要的是恰当选取特征.甚至创造特征的能力,这叫做特征选取和特征工程.对于特征选取工作,我个人认为分为两个方面: 1)利用python中已有的算法进行特征选取. 2)人为分析各个 ...

  3. 网络应用框架Netty快速入门

    一 初遇Netty Netty是什么? Netty 是一个提供 asynchronous event-driven (异步事件驱动)的网络应用框架,是一个用以快速开发高性能.可扩展协议的服务器和客户端 ...

  4. WmiPrvSE.exe进程(WMI Provider Host)不能删除

    WmiPrvSE.exe进程基本信息:程序厂商:微软® Microsoft Corp.进程描述:WMI Provider Host进程属性:Windows系统进程使用网络:是的启动情况:触发启动 来历 ...

  5. wait函数

    当一个进程正常或异常终止时,内核就向其父进程发送SIGCHLD信号.子进程终止是一个异步事件(其能够在父进程运行的任何时候发生). 对于wait(),其调用者,即父进程可以有如下状态: 如果其所有子进 ...

  6. iOS APP程序启动原理

    UIApplication 程序启动原理 一个应用程序运行就必须要有一个进程,一个进程至少要有一个线程,我们把这个线程叫做主线程,主线程开启之后会开启一个主运行循环,如果不开启一个运行循环,程序开启了 ...

  7. 重写Alert

    var isIE = navigator.appName.indexOf("Internet Explorer") != -1;var oldAlert = window.aler ...

  8. Network Embedding

    网络表示 网络表示学习(DeepWalk,LINE,node2vec,SDNE) https://blog.csdn.net/u013527419/article/details/76017528 网 ...

  9. linux命令(37):locate命令

    1.命令格式: Locate [选择参数] [样式] 2.命令功能: locate命令可以在搜寻数据库时快速找到档案,数据库由updatedb程序来更新,updatedb是由cron daemon周期 ...

  10. linux命令(36):which命令

    我们经常在linux要查找某个文件,但不知道放在哪里了,可以使用下面的一些命令来搜索:        which  查看可执行文件的位置.       whereis 查看文件的位置.         ...