社论 22.10.15 排列逆序对计数
之前对着第二维就是求和生成然后什么玩意都搞不出来 wssb
给定 \(n,k\),求长度为 \(n\) 、逆序对数为 \(k\) 的排列数量模 \(998244353\) 后的值。
\(n,k \le 3000\)。
考虑令 \(f_{i,j}\) 为长度为 \(i\),逆序对数为 \(j\) 的排列的数量。答案即为 \(f_{n,k}\)。
考虑通过插入计数。
我们首先有一个长度为 \(i\),逆序对数为 \(j\) 的排列。现在向其中插入元素 \(i+1\)。容易发现其插入在从前往后数的第 \(k\) 位置会导致其后面的 \((i-k+1)\) 个元素和它生成逆序对,因此 \(f_{i,j}\) 能贡献给 \(f_{i+1,j+i-k+1} \text{ s.t. } 0\le k \le i\)。
重写一下,我们有 \(dp\) 式:
然后能做到 \(O(n^2 k)\) 的复杂度。
我们发现后面的部分其实是一个前缀和差分的形式,因此维护一下前缀和能做到 \(O(nk\log n) \sim O(nk)\) 的复杂度。
O(nk log n)
#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;
#define rep(i,a,b) for (register int i = (a), i##_ = (b) + 1; i < i##_; ++i)
#define pre(i,a,b) for (register int i = (a), i##_ = (b) - 1; i > i##_; --i)
int n, m, x;
struct BIT {
int Index[3005];
int operator [] (int p) {
int ret = 0;
while (p) {
ret += Index[p];
p ^= p & -p;
} return ret;
}
void add(int p, int v) {
while (p <= n) {
Index[p] += v;
p += p & -p;
}
}
} f[3005];
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n >> m;
f[1].add(1, 1);
rep(i,2,n) {
rep(j,0,min((i * (i-1)) >> 1, n)) {
f[i].add(j + 1, (f[i-1][j + 1] - f[i-1][j - min(i-1,j)]));
}
} rep(i,1,m) {
cin >> x; x ++;
cout << (f[n][x] - f[n][x-1]) << '\n';
}
}
[能不能再给力一点啊?]
题面相同。
\(n,k \le 10^5\)
认为 \(n,k\) 同阶,因此下文中渐进式内只使用 \(n\)。
考虑对第二维求和得到生成函数
则答案即为 \([x^k]F_n(x)\)。
我们考虑转移方程。我们发现,\(j\) 位置能够从 \(j-1\sim j-i+1\) 转移过来。放在生成函数上,\(F_i(x)\) 可以通过 \(F_{i-1}(x)\sim x^{i-1}\times F_{i-1}(x)\) 转移过来。
于是有
考虑 \(f(x) = \prod_{i=1}^n (1-x^i)\) 和 \(g(x) = (1-x)^{-n}\) 的求法。
\(f(x)\) 是五边形数。有关五边形数:
五边形数定理 \(\text{ (Euler)}\)
设 \(\Phi(x)\) 为欧拉函数的生成函数。有下式:
\[\Phi(x) = \prod_{i=1}^n (1-x^i) = \sum_{i=0}^{\infty} (-1)^i x^{\frac{i(3i\pm 1)}{2}} \]
我们发现 \(f(x)\) 的幂级数形式只有 \(O(\sqrt n)\) 项有值。直接生成即可。这部分的复杂度为 \(O(\sqrt n)\)。
\(g(x)\) 可以直接通过多项式快速幂在 \(O(n\log n)\) 的复杂度内生成。
生成后直接做多项式卷积即可。复杂度 \(O(n \log n)\)。
[能不能再给力一点啊?]
题面相同。
\(k \le 10^5, n\le 10^{18}\)。
注意到在上文中我们只需要多项式中第 \(k\) 次项。因此直接从 \(k\) 位置截断即可得到最终答案。
随后我们可以在 \(O(\sqrt k)\) 的时间内生成 \(f\)。
随后我们可以使用多项式快速幂得到 \(g\)。
时间复杂度为 \(O(k\log k)\)。
使用生成函数方式证明 \(f\) 的行取值对称。
于是有
于是有
由于 \(F(x)\) 有意义的取值部分位于 \(x^0 \sim x^\frac {n(n-1)}2\) 部分,因此我们证明了 \(f_{n,i}\) 的取值的对称性。
关于“能不能再给力一点啊?”这件事,由于我多项式远处系数提取的功底不够扎实,先咕着。
以下是博客签名,与正文无关。
请按如下方式引用此页:
本文作者 joke3579,原文链接:https://www.cnblogs.com/joke3579/p/editorial221015.html。
遵循 CC BY-NC-SA 4.0 协议。
请读者尽量不要在评论区发布与博客内文完全无关的评论,视情况可能删除。