• 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');
    }
    
  • 相关阅读:
    HEC-ResSim原文档
    水文模型大全
    用word发布博客到博客园
    给你的浏览器标题栏加上小图标
    系统性能调优必知必会学习
    系统性能调优必知必会学习
    容器化学习
    Redisson学习
    mysql回顾
    事物、源码学习,spring-tx
  • 原文地址:https://www.cnblogs.com/AThousandMoons/p/16366616.html
Copyright © 2020-2023  润新知