『JLOI2016』成绩比较

『JLOI2016』成绩比较 [* easy]

给定 \(N\) 个变量,每个变量有 \(M\) 个属性,属性 \(i\) 的值在 \([1,U_i]\) 中随机。

\(1\) 个变量的所有属性的排名以及给出,然后我们知道恰好有 \(K\) 个变量满足所有属性都严格小于等于 \(1\)

求所有可能的合法情况。答案对 \(10^9+7\) 取模。

\(N,M\le 100,U_i\le 10^9\)

Solution

方便起见,令 \(N\leftarrow N-1\),同时令 \(R_j\leftarrow N+1-R_j\) 表示有 \(R_j\) 名同学分数小于等于他。

容斥,设 \(g_i\) 表示至少有 \(i\) 个变量严格小于等于他。

那么我们可以直接使用 Dp 来计算 \(g_i\),那么基础方案数为 \(\binom{N}{i}\),假设属性 \(j\) 的取值为 \(x\),那么这 \(i\) 个变量的取值范围均为 \(x\),那么对于每个属性对答案的贡献均可以独立乘起来,具体来说形如此:

\[\begin{aligned} &\binom{N-i}{R_j-i}\sum_{x=1}^{U_j}x^{R_j}(U_j-x)^{N-R_j} \end{aligned}\]

\(o=R_j\),不难得到:

\[\begin{aligned} &\binom{N-i}{o-i}\sum_{x=1}^{U_j}x^{o}(U_j-x)^{N-o} \\&\Rightarrow \binom{N-i}{o-i}\sum_{x=1}^{U_j}x^{o}\sum_j \binom{N-o}{j}(-1)^j x^jU_j^{N-o-j} \\&\Rightarrow \binom{N-i}{o-i}\sum_j \binom{N-o}{j}(-1)^j U_j^{N-o-j}\sum_{x=1}^{U_j}x^{o+j} \end{aligned}\]

\(f(k,x)=\sum_{i=1}^x i^k\)

那么不难得到维度 \(i\) 对答案的贡献为:

\[\begin{aligned} &\binom{N-i}{o-i}\sum_j \binom{N-o}{j}(-1)^j U_j^{N-o-j}f(o+j,U_j) \end{aligned}\]

显然 \(o+j\) 的取值范围为 \(1\sim N\),同时不难发现后面的式子与枚举的 \(i\) 无关,所以可以考虑预处理后式,对于 \(j=1,2...M\) 均预处理后式称为 \(t_j\),那么枚举 \(i\) 之后就可以 \(\mathcal O(NM)\) 的计算答案了。

我们的瓶颈在于希望得到正整数幂多项式,此时有两种选择:

  1. 拉格朗日插值。
  2. 伯努利数。

由于我想要复习伯努利数,所以这里又重新进行了推导:

\(S_k(n)=\sum_{j=1}^n j^k\)

\[\begin{aligned} &\sum_{k=0} S_k(n)\frac{x^k}{k!} \\&\Rightarrow\sum_{k=0}\sum_{j=1}^n \frac{j^kx^k}{k!} \\&\Rightarrow\sum_{j=1}^n e^{jx} \\&\Rightarrow\frac{e^{(n+1)x}-e^x}{e^x-1} \\&\Rightarrow\frac{xe^x}{e^x-1}\times \frac{e^{nx}-1}{x} \end{aligned}\]

我们设前者的 EGF 序列为 \(\{B_0,B_1...B_k\}\),后者为 \(\{\frac{n}{1},\frac{n^2}{2}...\frac{n^{i+1}}{i+1}\}\)

于是有 \(S_k(n)\) 即为:

\[\begin{aligned} &\sum_{i+j=k}B_i\binom{k}{i}\frac{n^{k-i+1}}{k-i+1} \\&\Rightarrow \frac{1}{k+1}\sum_{i+j=k}B_i\binom{k+1}{i}n^{k-i+1} \end{aligned}\]

计算 \(B_i\),然后直接得到多项式。

接下来,注意到:

\[\frac{xe^x}{e^x-1}\times \frac{e^x-1}{x}=e^x \]

所以有 \(\{B_0,B_1...B_k\}\)\(\{\frac{1}{1},\frac{1}{2}...\frac{1}{i+1}\}\) 的二项卷积结果为 \(\{1,1,1...1\}\)

不难注意到 \(B_0=1\),所以我们有:

\[B_k=1-\sum_{i<k}\binom{k}{i}B_i\frac{1}{k-i+1} \]

\[B_k=1-\frac{1}{k+1}\sum_{i<k}\binom{k+1}{i}B_i \]

复杂度为 \(\mathcal O(N^2M)\)

\(Code:\)

#include<bits/stdc++.h>
using namespace std ;
#define Next( i, x ) for( register int i = head[x]; i; i = e[i].next )
#define rep( i, s, t ) for( register int i = (s); i <= (t); ++ i )
#define drep( i, s, t ) for( register int i = (t); i >= (s); -- i )
#define re register
#define int long long
int gi() {
	char cc = getchar() ; int cn = 0, flus = 1 ;
	while( cc < '0' || cc > '9' ) {  if( cc == '-' ) flus = - flus ; cc = getchar() ; }
	while( cc >= '0' && cc <= '9' )  cn = cn * 10 + cc - '0', cc = getchar() ;
	return cn * flus ;
}
const int N = 100 + 5 ; 
const int P = 1e9 + 7 ;  
int fpow(int x, int k) {
	int ans = 1, base = x ;
	while(k) {
		if(k & 1) ans = 1ll * ans * base % P ;
		base = 1ll * base * base % P, k >>= 1 ;
	} return ans ;
}
int n, m, lim, K, U[N], R[N], g[N], h[N], B[N] ;
int f[N], iv[N], fac[N], inv[N], C[N][N], A[N][N] ; 
int Get(int x, int k) {
	int ans = 0, d = 1 ;
	for(re int i = 0; i <= k + 1; ++ i)
		ans = (ans + d * A[k][i]) % P, d = d * x % P ;
	return ans ; 
}
signed main()
{
	n = gi() - 1, m = gi(), K = gi() ; lim = n + 5 ; 
	rep( i, 1, m ) U[i] = gi() ; 
	rep( i, 1, m ) R[i] = gi(), R[i] = n - R[i] + 1 ; 
	fac[0] = inv[0] = C[0][0] = 1 ; 
	rep( i, 1, lim ) rep( j, 0, lim ) 
	C[i][j] = (!j) ? 1 : (C[i - 1][j - 1] + C[i - 1][j]) % P ; 
	rep( i, 1, lim ) 
		fac[i] = fac[i - 1] * i % P, inv[i] = fpow(fac[i], P - 2), 
		iv[i] = fpow( i, P - 2 ) ; 
	B[0] = 1 ; 
	rep( i, 1, n ) {
		int d = 0 ;
		rep( j, 0, i - 1 ) d = (d + C[i + 1][j] * B[j]) % P ; 
		d = d * iv[i + 1] % P, B[i] = (1 - d + P) % P ; 
	}
	rep( k, 0, n ) rep( i, 0, k ) 
		A[k][k - i + 1] = C[k + 1][i] * B[i] % P * iv[k + 1] % P ;
	rep( i, 1, m ) {
		int o = R[i], ans = 0 ; f[0] = 1 ; 
		rep( j, 1, n ) f[j] = f[j - 1] * U[i] % P ; 
		for(re int j = 0; j <= n - o; ++ j) {
			if(j & 1) ans = (ans - C[n - o][j] * f[n - o - j] % P * Get(U[i], o + j) % P + P) % P ; 
			else ans = (ans + C[n - o][j] * f[n - o - j] % P * Get(U[i], o + j) % P ) % P ;
		} h[i] = ans ; 
	}
	rep( i, 1, n ) {
		int ans = C[n][i] ; 
		rep( j, 1, m ) 
			if( R[j] < i ) ans = 0 ;
			else ans = ans * C[n - i][R[j] - i] % P * h[j] % P ; 
		g[i] = ans ; 
	}
	int Ans = 0 ; 
	rep( i, K, n ) {
		if((i - K) & 1) Ans = (Ans - g[i] * C[i][K] % P + P) % P ; 
		else Ans = (Ans + g[i] * C[i][K] % P + P) % P ; 
	}
	cout << Ans << endl ; 
	return 0 ;
}
posted @ 2020-10-10 15:59  Soulist  阅读(147)  评论(0编辑  收藏  举报