题解 P5367 【【模板】康托展开】

皎月半洒花

2019-05-13 17:01:13

Solution

一道zz题。 首先我们知道的康托展开,根据给定排列算位次的结论是以下代码: ```cpp inline void work_contor(ll *now){ ll k, l, t, res = 0; for(k = 1; k <= N; k ++){ t = 0 ; for(l = k + 1; l <= N; l ++) if(now[l] < now[k]) t ++ ; res += t * Flr[N - k] ; } cout << res + 1 << endl ; } ``` 我们试图优化这个东西。我们发现时间复杂度的瓶颈就在于,对于$a_i$我们不能快速统计$a_j < a_i,j > i$的二元组$<a_i, a_j>$的个数。我们发现这就是个逆序对,就可以直接上权值线段树来统计。 不得不说迄今为止这个题的数据还是太弱了。 ```cpp #include <cstdio> #include <iostream> #include <algorithm> #define rr register #define MAXN 1000100 #define Mod 998244353 using namespace std ; int T[MAXN << 1] ; int query[MAXN], Flr[MAXN], N, K, i, j, q ; inline void push_up(int rt){ T[rt] = T[rt << 1] + T[rt << 1 | 1] ; } inline void update(int rt, int l, int r, int p){ if (l == p && r == p) { T[rt] ++ ; return ; } rr int mid = (l + r) >> 1 ; if (p <= mid) update(rt << 1, l, mid, p) ; else update(rt << 1 | 1, mid + 1, r, p) ; push_up(rt) ; } inline int que(int rt, int l, int r, int ql, int qr){ if (ql > qr) return 0 ; if (ql <= l && qr >= r) return T[rt] ; rr int mid = (l + r) >> 1, res = 0 ; if (ql <= mid) res += que(rt << 1, l, mid, ql, qr) ; if (qr > mid) res += que(rt << 1 | 1, mid + 1, r, ql, qr) ; return res ; } inline void work_contor(int *now){ int k, l, t = 0, res = 0; for (k = 1 ; k <= N ; ++ k, t = 0) res = (1ll * res + 1ll * (now[k] - que(1, 1, N, 1, now[k] - 1) - 1) * Flr[N - k]) % Mod, update(1, 1, N, now[k]) ; cout << (res + 1) % Mod << endl ; } int main(){ cin >> N ; Flr[1] = Flr[0] = 1 ; for (i = 2; i <= N ; i ++) Flr[i] = 1ll * Flr[i - 1] * i % Mod ; for (j = 1; j <= N ; j ++) scanf("%d", &query[j]) ; work_contor(query) ; return 0 ; } ```