loading

JOISC2018D 修行 (Asceticism)

题意

给定 \(n,k\),求能被恰好分成 \(k\) 段上升序列,即恰好存在 \(k\)\(p_i>p_{i+1}\) 的位置 \(i\) 的排列 \(p\) 的个数,模数 \(10^9+7\)

\(n,k\le10^5\)

分析

其实就是欧拉数

有一个 \(O(n^2)\) 做法:设 \(f_{n,k}\) 表示答案。转移考虑 \(n\) 插入在上升序列末尾(贡献 0)或者其他地方(贡献 1),\(f_{n,k}=kf_{n-1,k}+(n-k+1)f_{n-1,k-1}\)。对正解没有启发作用。

考虑二项式反演,转而计算钦定 \(k\) 个位置 \(p_i>p_{i+1}\) 的方案数,这 \(k\) 个大于号能将原排列分成 \(n-k\) 段,段内序列递减。发现这个问题等价于将 \(n\) 个有标号的球划分到 \(n-k\) 个有标号盒子里,盒子之内的球没有顺序。这其实就是第二类斯特林数乘以阶乘 \(S(n,n-k)\cdot (n-k)!\)。考虑将 \(S(n,n-k)\) 用通项展开:

\[f_k=\sum_{i=0}^{n-k}(-1)^{n-k-i}\dbinom{n-k}{i}i^n \]

代入二项式反演式子(至少推恰好) \(g_k=\sum_{i=k}^n (-1)^{i-k}\dbinom{i}{k}f_i\)

\[g_k=\sum_{i=k}^n(-1)^{i-k}\dbinom{i}{k}\sum_{j=0}^{n-i}(-1)^{n-i-j}\dbinom{n-i}{j} j^n \]

\[=\sum_{j=0}^n(-1)^{n-k-j}j^n\sum_{i=0}^{n-j}\dbinom{i}{k}\dbinom{n-i}{j} \]

\[=\sum_{j=0}^n(-1)^{n-k-j}j^n\dbinom{n+1}{k+j+1} \]

第三步用到了一个组合恒等式 \(\sum_{i=0}^n\dbinom{i}{x}\dbinom{n-i}{y}=\dbinom{n+1}{x+y+1}\),证明考虑枚举一个特殊位置,然后让前面的选 \(x\) 个,后面的选 \(y\) 个,这等价于 \(n+1\) 个物品中选 \(x+y+1\) 个。

直接做即可,复杂度 \(O(n\log n)\)\(O(n)\)

多点求值可以套用 \(f_{k}=S(n,n-k)\cdot(n-k)!\) 直接第二类斯特林数行做。

int n,k;
int fac[maxn],inv[maxn];
int ksm(int x,int y){
	int res=1;
	for(;y;y>>=1,x=x*x%mod)if(y&1)res=res*x%mod;
	return res;
}
int C(int x,int y){
	if(x<y)return 0;
	return fac[x]*inv[y]%mod*inv[x-y]%mod;
}
void init(int lim){
	fac[0]=1;rep(i,1,lim)fac[i]=fac[i-1]*i%mod;
	inv[lim]=ksm(fac[lim],mod-2);per(i,lim-1,0)inv[i]=inv[i+1]*(i+1)%mod;
}
inline void solve_the_problem(){
	n=rd(),k=rd()-1;
	init(n+1);
	int ans=0;
	rep(i,0,n-k){
		int res=ksm(i,n)*C(n+1,k+i+1)%mod;
		if((n-k-i)%2==0)ans=(ans+res)%mod;
		else ans=(ans+mod-res)%mod;
	}
	write(ans);
}
posted @ 2025-02-19 16:37  dcytrl  阅读(47)  评论(1)    收藏  举报