CF1687F Koishi's Unconscious Permutation 【欧拉数,生成函数,FFT】

给定正整数 \(n\) 和非负整数 \(s\),求对所有满足 \(s=\sum_{i=1}^{n-1}[p_i+1=p_{i+1}]\) 的长为 \(n\) 的排列 \(p\),求 \(\sum_{i=1}^{n-1}[p_i<p_{i+1}]\) 的分布,模 \(998\,244\,353\)\(\newcommand\Euler[2]{\left\langle\!\begin{matrix}#1 \\ #2\end{matrix}\!\right\rangle}\)

\(s<n\le 2.5\cdot 10^5\)

前置知识:欧拉数的二元 GF。

\(\displaystyle\mathcal F(x,t)=\sum_{n\ge 0}\frac{x^n}{n!}\sum_{m=0}^n\Euler nm\cdot t^m\),考虑二项式反演,\([x^nt^m]\mathcal F(xt,1+t^{-1})\) 表示对长为 \(n\) 的排列钦定 \(n-m\) 个上升的方案数 \(/n!\),考虑这些 \(p_i<p_{i+1}\) 的限制,看成边之后形成 \(m\) 个连通块,每个连通块内部要求有序,相当于划分成 \(m\) 个集合,不同集合之间有顺序,也就是 \([x^n](\text e^x-1)^m\)(第二类斯特林数)。所以 \(\mathcal F(xt,1+t^{-1})=(1-(\text e^x-1)t)^{-1}\),从而 \(\mathcal F(x,t)=\dfrac{t-1}{t-\text e^{(t-1)x}}.\)

首先当然是把连续段缩一下:所有答案乘上 \(\binom{n-1}s\),然后令 \(n:=n-s\)\(k:=k-s\)\(s:=0\),容斥一下就得到:

\[\begin{aligned} \text{ans}_k&=\sum_{i=0}^k(-1)^i\binom{n-1}i\Euler{n-i}{n-k-1} \\ &=(n-1)![t^{n-k-1}]\sum_{i=0}^k\frac{(-1)^i}{i!}\cdot(n-i)[x^{n-i}]\frac{t-1}{t-\text e^{(t-1)x}} \\ &=(n-1)![t^{n-k-1}]\sum_{i=0}^k\frac{(-1)^i}{i!}[x^{n-i-1}]\frac{\partial}{\partial x}\frac{t-1}{t-\text e^{(t-1)x}} \\ &=(n-1)![t^{n-k-1}]\sum_{i=0}^k[x^i]\text e^{-x}\cdot[x^{n-i-1}]\frac{(t-1)^2\cdot\text e^{(t-1)x}}{(t-\text e^{(t-1)x})^2} \\ &=(n-1)![x^{n-1}t^{n-k-1}]\frac{(t-1)^2\cdot\text e^{(t-2)x}}{(t-\text e^{(t-1)x})^2} \\ &=(n-1)![x^{n-1}t^{n-k-1}]\frac{(t-1)^2\cdot\text e^{-tx}}{(t\cdot \text e^{(1-t)x}-1)^2} \\ &=(n-1)![y^{n-1}t^{n-k-1}]\frac{(1-t)^{n+1}\cdot\text e^{-\frac t{1-t}y}}{(1-t\cdot\text e^y)^2}\pod{y=(1-t)x} \\ &=(n-1)![t^{n-k-1}](1-t)^{n+1}\cdot[y^{n-1}]\sum_{i\ge 0}(i+1)t^i\cdot\text e^{(i-s)y}\pod{s=\frac t{1-t}} \\ &=(n-1)![t^{n-k-1}](1-t)^{n+1}\left([y^{n-1}]\sum_{i\ge 0}\left(i-\frac t{1-t}\right)t^i\cdot\text e^{(i-s)y}+\frac 1{1-t}[y^{n-1}]\sum_{i\ge 0}t^i\cdot\text e^{(i-s)y}\right) \\ &=[t^{n-k-1}]\left((1-t)^{n+1}n![y^n]+(1-t)^n(n-1)![y^{n-1}]\right)\sum_{i\ge 0}t^i\cdot\text e^{(i-s)y} \\ &=[t^{n-k-1}]\left((1-t)^{n+1}n![y^n]+(1-t)^n(n-1)![y^{n-1}]\right)\frac{(w+1)^{-s}}{1-t(w+1)}\pod{w=\text e^y-1} \\ (1-t)^{n+1}n![y^n]\frac{(w+1)^{-s}}{1-t(w+1)}&=(1-t)^{n+1}n!\sum_{m=0}^n[y^n](\text e^y-1)^m\cdot[w^m]\frac 1{1-t(w+1)}\sum_{i\ge 0}\binom{-s}iw^i\\ &=(1-t)^n\sum_{m=0}^nm!{n\brace m}[w^m]\frac 1{1-sw}\sum_{i\ge 0}\binom{-s}iw^i \\ &=(1-t)^n\sum_{m=0}^nm!{n\brace m}\sum_{i=0}^m\binom{-s}is^{m-i} \end{aligned} \]

现在问题就是求这玩意,首先我们只用求后面和式写成 \(s\) 的多项式,换成 \(t\) 就是说 \(s^i\to t^i(1-t)^{n-i}\),即 \((-1)^{j-i}\binom{n-i}{j-i}[s^i]\to[t^j]\),这是卷积形式。

考虑分治,设 \(c_m\) 是 Stirling 数的那个系数,对区间 \((l,r]\) 计算 \(\sum_{m=l+1}^rc_m\sum_{i=l+1}^ms^{m-i}(-s-l)^{\underline{i-l}}/i^{\underline{i-l}}\),分类讨论 \(i,m\) 在中点的哪边,可知再算 \(\sum_{i=l+1}^rs^{r-i}(-s-l)^{\underline{i-l}}/i^{\underline{i-l}}\)\(\sum_{i=l+1}^rc_is^{i-l}\)\((-s-l)^{\underline{r-l}}/r^{\underline{r-l}}\) 就可以了,最后特判一下 \(i=0\) 的贡献。时间复杂度 \(\mathcal O(n\log^2n)\)

因为空间复杂度 \(\mathcal O(n)\) 所以空间占用排到了 rk1,不过没啥用

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef vector<int> Poly;
const int N = 1 << 19, mod = 998244353;
int ksm(int a, int b){
	int res = 1;
	for(;b;b >>= 1, a = (LL)a * a % mod)
		if(b & 1) res = (LL)res * a % mod;
	return res;
}
int n, s, fac[N], ifac[N], inv[N], w[N];
int C(int a, int b){
	if(b < 0 || a < b) return 0;
	return (LL)fac[a] * ifac[b] % mod * ifac[a - b] % mod;
}
int rev[N], lim;
void calrev(int len){
	int L = -1; lim = 1;
	while(lim <= len){lim <<= 1; ++ L;}
	for(int i = 1;i < lim;++ i)
		rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << L);
}
void NTT(int *A, bool op){
	for(int i = 0;i < lim;++ i)
		if(i < rev[i]) swap(A[i], A[rev[i]]);
	for(int md = 1;md < lim;md <<= 1)
		for(int i = 0;i < lim;i += md << 1)
			for(int j = 0;j < md;++ j){
				int y = (LL)A[md + i + j] * (op && j ? mod - w[(md << 1) - j] : w[md + j]) % mod;
				if((A[md + i + j] = A[i + j] - y) < 0) A[md + i + j] += mod;
				if((A[i + j] += y) >= mod) A[i + j] -= mod;
			}
	if(op){
		int inv = ksm(lim, mod - 2);
		for(int i = 0;i < lim;++ i) A[i] = (LL)A[i] * inv % mod;
	}
}
Poly operator + (const Poly &a, const Poly &b){
	Poly res(max(a.size(), b.size()));
	for(int i = 0;i < res.size();++ i)
		if((res[i] = (i < a.size() ? a[i] : 0) + (i < b.size() ? b[i] : 0)) >= mod) res[i] -= mod;
	return res;
}
int A[N], B[N];
Poly operator * (const Poly &a, const Poly &b){
	Poly res(a.size() + b.size() - 1);
	if(res.size() <= 50){
		for(int i = 0;i < a.size();++ i)
			for(int j = 0;j < b.size();++ j)
				res[i + j] = (res[i + j] + (LL)a[i] * b[j]) % mod;
	} else {
		calrev(res.size());
		memset(A, 0, lim << 2);
		memset(B, 0, lim << 2);
		for(int i = 0;i < a.size();++ i) A[i] = a[i];
		for(int i = 0;i < b.size();++ i) B[i] = b[i];
		NTT(A, 0); NTT(B, 0);
		for(int i = 0;i < lim;++ i) A[i] = (LL)A[i] * B[i] % mod;
		NTT(A, 1);
		for(int i = 0;i < res.size();++ i) res[i] = A[i];
	}
	return res;
}
Poly shl(Poly a, int k){a.insert(a.begin(), k, 0); return a;}
Poly Stir2(int n){
	Poly a(n + 1), b(n + 1);
	for(int i = 0;i <= n;++ i){
		a[i] = (LL)ksm(i, n) * ifac[i] % mod;
		b[i] = (i & 1) ? mod - ifac[i] : ifac[i];
	}
	a = a * b; a.resize(n + 1);
	for(int i = 0;i <= n;++ i) a[i] = (LL)a[i] * fac[i] % mod;
	return a;
}
Poly coe;
struct Node {Poly prd, sm0, sm1, sm2;};
Node work(int l, int r){
	if(r - l == 1){
		Node ans;
		ans.prd.resize(2); ans.prd[1] = mod - inv[r]; ans.prd[0] = (LL)l * ans.prd[1] % mod;
		ans.sm0.resize(2); ans.sm0[1] = coe[r]; ans.sm1 = ans.prd;
		ans.sm2.resize(2); ans.sm2[0] = (LL)ans.prd[0] * coe[r] % mod; ans.sm2[1] = (LL)ans.prd[1] * coe[r] % mod;
		return ans;
	}
	int md = l + r >> 1;
	Node ls = work(l, md), rs = work(md, r), res;
	res.prd = ls.prd * rs.prd;
	res.sm0 = ls.sm0 + shl(rs.sm0, md - l);
	res.sm1 = shl(ls.sm1, r - md) + rs.sm1 * ls.prd;
	res.sm2 = ls.sm2 + rs.sm2 * ls.prd + ls.sm1 * rs.sm0;
	return res;
}
Poly solve(int n){
	coe = Stir2(n);
	Node $ = work(0, n);
	Poly ans = $.sm2 + $.sm0, b(n + 1);
	for(int i = 0;i <= n;++ i){
		ans[i] = (LL)ans[i] * fac[n - i] % mod;
		b[i] = (i & 1) ? mod - ifac[i] : ifac[i];
	}
	ans = ans * b; ans.resize(n + 1);
	for(int i = 0;i <= n;++ i) ans[i] = (LL)ans[i] * ifac[n - i] % mod;
	return ans;
}
int main(){
	ios::sync_with_stdio(0);
	cin >> n >> s; *fac = 1;
	for(int i = 1;i < N;++ i) fac[i] = (LL)fac[i - 1] * i % mod;
	ifac[N - 1] = ksm(fac[N - 1], mod - 2);
	for(int i = N - 1;i;-- i){
		ifac[i - 1] = (LL)ifac[i] * i % mod;
		inv[i] = (LL)ifac[i] * fac[i - 1] % mod;
	}
	for(int md = 1;md < N;md <<= 1){
		int Wn = ksm(3, (mod - 1) / (md << 1)); w[md] = 1;
		for(int i = 1;i < md;++ i) w[md + i] = (LL)w[md + i - 1] * Wn % mod;
	}
	int coef = C(n - 1, s); n -= s;
	if(n == 1){
		for(int i = 0;i < s;++ i){putchar('0'); putchar(' ');}
		puts("1"); return 0;
	}
	Poly ans = solve(n) + solve(n - 1);
	for(int i = 0;i < s;++ i){putchar('0'); putchar(' ');}
	for(int i = n - 1;i >= 0;-- i) printf("%lld ", (LL)ans[i] * coef % mod);
	putchar('\n');
}
posted @ 2022-06-11 19:30  mizu164  阅读(343)  评论(2编辑  收藏  举报