Loading

CF1516E Baby Ehab Plays with Permutations

CF1516E Baby Ehab Plays with Permutations

发现交换 \(k\) 次意味着至少 \(n-k\) 个循环。

交换次数还要和 n-循环数 \(\bmod 2\) 同余,因为每交换一次要么循环数少一个,要么多一个。

可以发现满足以上两个条件的排列一定可以得到。

于是通过第一类斯特林数来统计,答案就是

\[ans_k=\sum_{i=n-k}^{n}[i\bmod 2 = k\bmod 2]S_1(n,i) \]

\(S_1\) 就是第一类斯特林数。

也就是说要求第一类斯特林数的后 \(k\) 项。

众所周知

\[x^{\overline{n}}=\prod_{i=0}^{n-1}(x+i)=\sum_{i=0}^{n}\begin{bmatrix}n\\i\end{bmatrix}x^i \]

如果把常数 \(i\) 乘到 \(x\) 上,我们就只需要提取前 \(k\) 项,方便许多,也就是我们转而计算

\[\prod_{i=0}^{n}(1+ix) \]

\(k\) 项。

\[f(x)=\prod_{i=0}^{n-1}(1+ix) \]

套路取 \(\ln\)\(\exp\)

\[\ln f(x)=\sum_{i=0}^{n-1}\ln (1+ix) \]

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

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

后面是自然数幂和前缀和。

可以构造 EGF 来计算:

\[\sum_{j=0}^{n-1}\sum_{i=0}^{n-1}i^j\dfrac{x^j}{j!} =\sum_{j=0}^{n-1}e^{ix}=\dfrac{1-e^{nx}}{1-e^x} \]

注意分母常数项为 \(0\),要上下同时除以 \(x\) 再计算。

如果换成 MTT 可以 \(O(k\log k)\),但是这么小数据范围不是很划算。于是我去补了套 \(O(n^2)\) 的全家桶qwq

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define mkp make_pair
#define pb push_back
#define sz(v) (int)(v).size()
typedef long long LL;
typedef double db;
template<class T>bool ckmax(T&x,T y){return x<y?x=y,1:0;}
template<class T>bool ckmin(T&x,T y){return x>y?x=y,1:0;}
#define rep(i,x,y) for(int i=x,i##end=y;i<=i##end;++i)
#define per(i,x,y) for(int i=x,i##end=y;i>=i##end;--i)
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=0;ch=getchar();}
	while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
	return f?x:-x;
}
const int N = 205;

namespace poly {
#define mod 1000000007
inline int qpow(int n, int k) {
	int res = 1;
	for(; k; k >>= 1, n = 1ll * n * n % mod)
		if(k & 1) res = 1ll * n * res % mod;
	return res; 
}
int inv[N], fac[N], ifc[N];
inline void init(const int &n = N - 1) {
	inv[1] = 1;
	for(int i = 2; i <= n; ++i) inv[i] = 1ll * inv[mod % i] * (mod - mod / i) % mod;
	fac[0] = 1;
	for(int i = 1; i <= n; ++i) fac[i] = 1ll * i * fac[i - 1] % mod;
	ifc[n] = qpow(fac[n], mod - 2);
	for(int i = n - 1; i >= 0; --i) ifc[i] = 1ll * ifc[i + 1] * (i + 1) % mod;
}
vector <int> operator * (const vector <int> &a, const vector <int> &b) {
	int n = a.size(), m = b.size();
	vector <int> res(n + m - 1, 0);
	for(int i = 0 ; i < n; ++i)
		for(int j = 0; j < m; ++j)
			res[i + j] = (res[i + j] + 1ll * a[i] * b[j]) % mod;
	return res;
}
vector <int> poly_inv(const vector <int> &a) {
	int n = a.size();
	vector <int> res(n);
	res[0] = qpow(a[0], mod - 2);
	for(int i = 1; i < n; ++i) {
		int tmp = 0;
		for(int j = 0; j < i; ++j)
			tmp = (tmp + 1ll * res[j] * a[i - j]) % mod;
		res[i] = 1ll * qpow(a[0], mod - 2) * (mod - tmp) % mod;
	}
	return res;
}
vector <int> deriv(const vector <int> &a) {
	int n = a.size();
	vector <int> res;
	if(n == 1) return res;
	res.resize(n - 1);
	for(int i = 0; i < n - 1; ++i) 
		res[i] = 1ll * a[i + 1] * (i + 1) % mod;
	return res;
}

vector <int> integ(const vector <int> &a) {
	int n = a.size();
	vector <int> res(n + 1);
	res[0] = 0;
	for(int i = 1; i < n; ++i)
		res[i] = 1ll * a[i - 1] * inv[i] % mod;
	return res;
}
vector <int> poly_ln(const vector <int> &a) {
	int n = a.size();
	vector <int> res = integ(deriv(a) * poly_inv(a));
	res.resize(n);
	return res;
}
vector <int> poly_exp(const vector <int> &a) {
	int n = a.size();
	vector <int> res(n);
	res[0] = 1;
	for(int i = 1; i < n; ++i) {
		int tmp = 0;
		for(int j = 0; j < i; ++j)
			tmp = (tmp + 1ll * a[j + 1] * (j + 1) % mod * res[i - 1 - j]) % mod;
		res[i] = 1ll * tmp * inv[i] % mod;
	}
	return res;
}

}
using namespace poly;

int n, k;
signed main() {
	cin >> n >> k, ++k, init();
	vector <int> a(k), b(k), ans(k);
	for(int i = 0, j = n; i < k; ++i, j = 1ll * j * n % mod)
		a[i] = 1ll * j * ifc[i + 1] % mod, b[i] = ifc[i + 1];
	a = a * poly_inv(b), a.resize(k);
	for(int i = 0; i < k; ++i) a[i] = 1ll * fac[i] * a[i] % mod;
	b[0] = 0;
	for(int i = 1; i < k; ++i) {
		int tmp = 1ll * a[i] * inv[i] % mod;
		b[i] = i & 1 ? tmp : mod - tmp;
	}
	b = poly_exp(b);
	for(int i = 0; i < k; ++i) {
		ans[i] = b[i];
		if(i - 2 >= 0) ans[i] = (ans[i] + ans[i - 2]) % mod;
	}
	for(int i = 1; i < k; ++i) printf("%d ", ans[i]);
	return 0; 
}
posted @ 2021-04-22 10:35  zzctommy  阅读(123)  评论(0编辑  收藏  举报