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;
}
路漫漫其修远兮,吾将上下而求索