CF1516E Baby Ehab Plays with Permutations
发现交换 (k) 次意味着至少 (n-k) 个循环。
交换次数还要和 n-循环数 (mod 2) 同余,因为每交换一次要么循环数少一个,要么多一个。
可以发现满足以上两个条件的排列一定可以得到。
于是通过第一类斯特林数来统计,答案就是
[ans_k=sum_{i=n-k}^{n}[imod 2 = kmod 2]S_1(n,i)
]
(S_1) 就是第一类斯特林数。
也就是说要求第一类斯特林数的后 (k) 项。
众所周知
[x^{overline{n}}=prod_{i=0}^{n-1}(x+i)=sum_{i=0}^{n}egin{bmatrix}n\iend{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^jdfrac{x^j}{j!}
=sum_{j=0}^{n-1}e^{ix}=dfrac{1-e^{nx}}{1-e^x}
]
注意分母常数项为 (0),要上下同时除以 (x) 再计算。
如果换成 MTT 可以 (O(klog 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;
}