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)\) 用通项展开:
代入二项式反演式子(至少推恰好) \(g_k=\sum_{i=k}^n (-1)^{i-k}\dbinom{i}{k}f_i\):
第三步用到了一个组合恒等式 \(\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);
}

浙公网安备 33010602011771号