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

首先我们要知道怎么算一个给定排列的排名,设它为$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. TOYS(计算几何基础+点与直线的位置关系)

    题目链接:http://poj.org/problem?id=2318 题面: TOYS Time Limit: 2000MS   Memory Limit: 65536K Total Submiss ...

  2. Winform GDI+

    什么是GDI+ GDI (Graphics Device Interface), 是属于绘图方面的 API (Application Programming Interface). 因为应用程序不能直 ...

  3. 关于EditText.setText()无法显示的问题

    将EditText在初始化后调用EditText.setSaveEnabled(false); 让Android 系统不保存值,这样就不会恢复了.

  4. thread线程栈size及局部变量最大可分配size【转】

    转自:http://blog.csdn.net/sunny04/article/details/46805261 版权声明:本文为博主原创文章,未经博主允许不得转载. 进程是操作系统的最小资源管理单元 ...

  5. Composer 手动安装

    Linux/Mac 环境 sudo wget -O /usr/local/bin/composer https://dl.laravel-china.org/composer.phar sudo ch ...

  6. expect 实现iterm2自动加载pem登录跳板机

    #!/usr/bin/expect set timeout spawn expect { "connecting (yes/no)?" { send "yes\r&quo ...

  7. 微信小程序的下拉刷新

    微信小程序的下拉刷新:在page的js文件中有监听用户下拉刷新的处理函数onPullDownRefresh:function(){} //js文件中自带的处理函数,在onUnload下面,注意不要重复 ...

  8. mybatis开启字段自动映射为java驼峰命名规则

    <settings> <setting name="mapUnderscoreToCamelCase" value="true"/> & ...

  9. 解决Ubuntu的错误提示

    如果你是一个Ubuntu用户,也许偶尔甚至经常,遇到这样一个错误提示“System Program problem detected”. Ubuntu有一个内建的实用程序叫做Apport, 当一个程序 ...

  10. hdu 1065(贪心)

    Wooden Sticks Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 20938   Accepted: 8872 De ...