今日模拟赛 T1
它题解讲的依托答辩。
答案即为本质不同的可以得到的所有序列。
可能的前置知识:符号化。当然其实不会也没关系,你就知道下面花体字是个集合就行了。
考虑将答案写作 egf 形式,记为 \(F(x)\)。也就是说,我们将答案序列看做弱标号对象,它们的全体组成了有标号类 \(\mathcal F\)。容易证明的是一定存在一个 \(\mathcal G\) 满足 \(\mathcal F = \text{SET}(\mathcal G)\),也就是 \(F(x) = \exp G(x)\)。
考虑归并两个排列时若上下存在相同的值,则我们可以随意选择两个排列中的一个,将一段数字归并入长序列。这就给出了两个排列的一系列划分,每个部分可以随意决定两个排列的子段在答案序列中的先后顺序,与其他部分互不干扰。举例来说,当上下两段的前七个数字分别为 \((1, 6, 5, 3, 7, 2, 4, \dots) \quad (1, 6, 2, 3, 7, 4, 5, \dots)\) 时,我们对下标能划分为 \(([1, 1], [2, 4], [5, 7], \dots)\)。模拟归并过程即可得到这划分。将这划分的组合看做 \(\text{Set}\) 构造(多项式 \(\exp\))即得。另一种思考方向是将排列拆成置换环,我没细想。
考虑 \(F(x)^2\) 的组合意义。
我们选择两个组合对象 \(a_1, a_2\in \mathcal F\),对应的序列长度为 \(2i, 2j\),他们定是由两个强标号的排列互相交错得到的。我们定义他们的乘法即为对两个强标号排列分别作重标号,方法共有 \(\dbinom{i + j}{i}\) 种。这样我们就能得到一个长度为 \(2(i + j)\) 的新排列。注意到由于 \(a\) 弱标号,这样得到的组合类会有重复。可以证明这样得到的组合类就是可以得到的所有序列组成的组合类。
我们考虑最终答案一定形如 \(i\ge 1,\ f_i\in \mathcal F\) 的重标号并列,也就是去掉本质不同的限制,而这由 \(\mathcal F = \text{SET}(\mathcal G)\) 可以退化到两个元素的并列。因此有如上结论。
考虑 \([x^n/n!]F(x)^2\) 的提取。
我们知道,若两个排列的划分数量为 \(k\),则它对答案的贡献为 \(2^k\)。记一对排列 \((\pi, \pi')\) 的划分数量为 \(\text{div}(\pi, \pi')\),则我们可以得到
前一个等号由组合意义得来,显然。后一个等号题解说考虑 \(1\) 的贡献,我由于没理解所以先把式子放在上面。
这也就可以在 \(O(n)\) 的复杂度内得到 \(F(x)^2\),随后作多项式开根即得答案。
我不清楚为何有人会套取数据过题。还是说不想把 1e5 的表压缩?
如果有多项式板子的话代码很简单。
code
signed main() {
cin >> n;
poly f(n + 1);
f[0] = 1; int va = 1;
rep(i,1,n) {
va = 1ll * va * (1ll * i * i % mod + 1) % mod;
f[i] = 1ll * va * gifc(i) % mod;
}
f = f.sqrt();
cout << 1ll * f[n] * gfac(n) % mod << '\n';
}