传送门


【分析】

先推一波公式:

答案 resres 显然有公式:(其中 DnD_n 表示 nn 个元素全部错排的方案数)

res=1n!x=0n(nx)xkDnx=x=0nxkx!Dnx(nx)!\begin{aligned}res&={1\over n!}\sum_{x=0}^n\dbinom n x x^kD_{n-x}\\&=\sum_{x=0}^n{x^k\over x!}\cdot {D_{n-x}\over (n-x)!}\end{aligned}

由于错排问题有公式:Dn=n!e=n!i=0n(1)ii!\displaystyle D_n=\lfloor{n!\over e}\rfloor=n!\cdot \sum_{i=0}^n{(-1)^i\over i!}

因此答案为:res=x=0nxkx!i=0nx(1)ii!\displaystyle res=\sum_{x=0}^n {x^k\over x!}\cdot \sum_{i=0}^{n-x} {(-1)^i\over i!}

xkx^k 用第二类斯特林数展开为下降幂,得到:

res=x=0nxkx!i=0nx(1)ii!=t=0k{kt}x=0nxtx!i=0nx(1)ii!=t=0min(n,k){kt}x=0nt1x!i=0(nt)x(1)ii!=t=0min(n,k){kt}T=0nti+j=T1j!(1)ii!=t=0min(n,k){kt}[1+T=1nt1T!i+j=T(Ti,j)(1)i]=t=0min(n,k){kt}[1+T=1nt1T!(11)T]=t=0min(n,k){kt}=Bellkt=n+1k{kt}\begin{aligned}res&=\sum_{x=0}^n {x^k\over x!}\cdot \sum_{i=0}^{n-x} {(-1)^i\over i!}\\&=\sum_{t=0}^k\begin{Bmatrix}k\\t\end{Bmatrix}\sum_{x=0}^n{x^{\underline t}\over x!}\cdot \sum_{i=0}^{n-x}{(-1)^i\over i!}\\&=\sum_{t=0}^{\min(n, k)}\begin{Bmatrix}k\\t\end{Bmatrix}\sum_{x=0}^{n-t}{1\over x!}\cdot \sum_{i=0}^{(n-t)-x}{(-1)^i\over i!}\\&=\sum_{t=0}^{\min(n, k)}\begin{Bmatrix}k\\t\end{Bmatrix}\sum_{T=0}^{n-t}\sum_{i+j=T}{1\over j!}\cdot {(-1)^i\over i!}\\&=\sum_{t=0}^{\min(n, k)}\begin{Bmatrix}k\\t\end{Bmatrix}[1+\sum_{T=1}^{n-t}{1\over T!}\sum_{i+j=T}\dbinom T {i, j}(-1)^i]\\&=\sum_{t=0}^{\min(n, k)}\begin{Bmatrix}k\\t\end{Bmatrix}[1+\sum_{T=1}^{n-t}{1\over T!}\cdot (1-1)^T]\\&=\sum_{t=0}^{\min(n, k)}\begin{Bmatrix}k\\t\end{Bmatrix}\\&=Bell_k-\sum_{t=n+1}^k\begin{Bmatrix}k\\t\end{Bmatrix}\end{aligned}


现在的问题化为,如何求解出 BellkBell_k{kt}\begin{Bmatrix}k\\t\end{Bmatrix}

关于前者,根据题解提到的 Touchard 同余,可以得到贝尔数在模质数 pp 意义下,有 BellnBellnp+Belln(p1)(modp)Bell_n\equiv Bell_{n-p}+Bell_{n-(p-1)}\pmod {p}

这显然是一个 pp 阶线性递推的形式,可以在 O(p2logk)O(p^2\log k) 的时间内求解出 BellkmodpBell_k\bmod p 的答案

而关于第二类斯特林数,有公式:

{xxn}=k=0n1<<nk>>(x+nk12n)\displaystyle \begin{Bmatrix}x\\x-n\end{Bmatrix}=\sum_{k=0}^{n-1}\left<\left<\begin{matrix}n\\k\end{matrix}\right>\right>\dbinom {x+n-k-1} {2n}

其中,<<nk>>\displaystyle \left<\left<\begin{matrix}n\\k\end{matrix}\right>\right> 为第二类欧拉数,或二阶欧拉数。它表示多重集 {1,1,2,2,,n,n}\{1, 1, 2, 2, \cdots, n, n\} 构成的序列中,任意两个相同的 ii 之间,所有数字都大于 ii 的序列方案数。如 123321123321 是满足要求的,但 123123123123 不是,因为两个 22 之间含有小于 2211 ;两个 33 之间含有小于 331,21,2

第二类欧拉数有递推公式: <<nk>>=(2nk1)<<n1k1>>+(k+1)<<n1k>>\displaystyle \left<\left<\begin{matrix}n\\k\end{matrix}\right>\right>=(2n-k-1)\left<\left<\begin{matrix}n-1\\k-1\end{matrix}\right>\right>+(k+1)\left<\left<\begin{matrix}n-1\\k\end{matrix}\right>\right>

因此,模数为小质数 pp 时,我们可以采用 O(p2logk)O(p^2\log k) 的时间求解 BellkmodpBell_k\bmod pO(p2)O(p^2) 递推 (nm)(0n,m<p)\dbinom n m (0\leq n,m<p) 的数值,然后再在 O((kn)2)O((k-n)^2) 的时间内地推出所有 O(kn)O(k-n) 的第二类欧拉数,最后对于每个 {kt}\begin{Bmatrix}k\\t\end{Bmatrix} 利用第二类欧拉数和 Lucas 定理进行 O((kt)logk)O((k-t)\log k) 求解

总复杂度为 O(p2logk)+O(p2)+O((kn)2)+t=n+1kO((kt)logk)=O(p2logk+(kn)2logk)\displaystyle O(p^2\log k)+O(p^2)+O((k-n)^2)+\sum_{t=n+1}^k O((k-t)\log k)=O(p^2\log k+(k-n)^2\log k)

然而,我们的模数 862118861=857×997×1009862118861=857\times 997\times 1009 是个合数,不适用上面的算法。这当然很好解决,我们单独跑每个质数的结果,最后用中国剩余定理合并即可


【代码】

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef vector<int> vi;
#define de(x) cout << #x <<" = "<<(x)<<endl
#define dd(x) cout << #x <<" = "<<(x)<<" "
#define all(a) a.begin(), a.end()
#define rep(i, a, b) for(int i=(a); i<(b); ++i)
#define per(i, a, b) for(int i=(b)-1; i>=(a); --i)
const int P=862118861, p[]={0, 857, 997, 1009};
ll n, k, S[1024][1024], Bell[1024];
inline ll kpow(ll a,ll x, ll p) { ll ans=1; for(;x;x>>=1, a=a*a%p) if(x&1) ans=ans*a%p; return ans; }
inline ll inv(ll a, ll p) { return kpow(a, p-2, p); }

int linear_recurrence(ll n, int m, vi a, vi c, int P) {
	if (n<m) return (a[n]+P)%P;
	vector<ll> v(m, 0), u(m<<1, 0);
	v[0] = 1;
	for(ll x = 0, W = n ? 1ll<<(63 - __builtin_clzll(n)) : 0; W; W >>= 1, x <<= 1) {
		fill(all(u), 0);
		int b = !!(n & W); if(b) x++;
		if(x < m) u[x] = 1;
		else {
			rep(i, 0, m) rep(j, 0, m) (u[i + b + j] += v[i] * v[j]) %= P;
			per(i, m, 2*m) rep(j, 0, m) (u[i - m + j] += c[j] * u[i]) %= P;
		}
		copy(u.begin(), u.begin() + m, v.begin());
	}
	ll ans = 0;
	rep(i, 0, m) (ans += v[i] * a[i]) %= P;
	return (ans+P)%P;
}

vi linear_a, linear_c;
inline int work_bell(ll k, int p) {
	linear_a.clear();
	linear_c.clear();
	S[0][0]=1;
	Bell[0]=1;
	linear_a.push_back(Bell[0]);
	for(int i=1; i<=p; ++i) {
		for(int j=1; j<=i; ++j)
			S[i][j]=(S[i-1][j-1]+(ll)S[i-1][j]*j)%p;
		Bell[i]=0;
		for(int j=1; j<=i; ++j)
			Bell[i]=(Bell[i]+S[i][j])%p;
		linear_a.push_back(Bell[i]);
	}
	linear_c.resize(p);
	linear_c[0]=linear_c[1]=1;
	return linear_recurrence(k, p, linear_a, linear_c, p);
}

int Euler2[5010][5010], C[1024][1024];
inline void pre_Euler2(int p) {
	Euler2[0][0]=1;
	for(int n=1; n<=5000; ++n) {
		Euler2[n][0]=1;
		for(int k=1; k<=n; ++k)
			Euler2[n][k]=((2ll*n-k-1)*Euler2[n-1][k-1]+(k+1ll)*Euler2[n-1][k])%p;
	}
}
inline void pre_C(int p) {
	C[0][0]=1;
	for(int i=1; i<p; ++i) {
		C[i][0]=C[i][i]=1;
		for(int j=1; j<i; ++j)
			C[i][j]=(C[i-1][j]+C[i-1][j-1])%p;
	}
}
inline int Lucas(ll n, ll m, int p) {
	int res=1;
	for(; n||m; n/=p, m/=p)
		res=(ll)res*C[n%p][m%p]%p;
	return res;
}
inline int S2(ll x, int n, int p) {
	int res=0;
	for(int k=0; k<=n; ++k)
		res=(res+(ll)Euler2[n][k]*Lucas(x+n-k-1, n+n, p))%p;
	return res;
}
inline int work(int p) {
	int res=work_bell(k, p);
	pre_Euler2(p);
	pre_C(p);
	for(ll t=n+1; t<=k; ++t)
		res=(res-S2(k, k-t, p))%p;
	return res<0?res+p:res;
}
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin>>n>>k;
	int x1=work(p[1]);
	int x2=work(p[2]);
	int x3=work(p[3]);
	ll m1=P/p[1], m2=P/p[2], m3=P/p[3];
	ll res=x1*m1*inv(m1, p[1])+x2*m2*inv(m2, p[2])+x3*m3*inv(m3, p[3]);
	cout<<res%P;
	cout.flush();
	return 0;
}