loj 2719 「NOI2018」冒泡排序 - 组合数学
显然要考虑一个排列p合法的充要条件。
考虑这样一个构造p的过程。设排列p−1i满足pp−1i=i。
- 初始令q=(1,2,⋯,n)。
- 依次考虑i=1,2,⋯,n。
- 设x=pi,如果q−1x>i,那么交换qx,qx−1。
上述算法每次交换的时候会使逆序对增加1。
考虑给出的下界,假设交换的是i和i+1。
不难用归纳法证明pi⩽。
那么考虑 \Delta = (i + 1 - p_i + |p_{i + 1} - i|) - (i - p_i + |p_{i + 1} - i - 1|)。
- 如果p_{i + 1} \geqslant i + 1,那么有 \Delta = (i + 1 - p_i + p_{i + 1} - i) - (i - p_i + p_{i + 1} - i - 1) =2
- 如果p_{i + 1} \leqslant i,那么有\Delta = (i + 1 - p_i + i - p_{i + 1}) - (i - p_i + i + 1 - p_{i + 1}) = 0
每次改变量要么为0,要么为2,如果某一次为0,那么将永远达不到下界。
因此序列合法当仅当上述算法中,每次交换满足q_x \geqslant x。
上述算法中,未确定的数并且可以向前移动的是一段后缀,并且满足q_x = x。
假如某次将y向前移动,那么如果一个z < y,并且z未确定,那么你不能将z向前移动。
然后考虑一下没有字典序限制怎么做,显然这个问题不会更难。
设f_{i, j}表示考虑到排列的前i个数,其中最大值为j。
转移考虑最大值有没有发生改变。
(i, j)是平面上的一个点,考虑把这个问题转化到平面上。
最大值改变等于可以向上走若干步,不变相当于向右走一步。
另外还需要满足i \geqslant j。
用折线法可以轻松计算出方案数。
然后我们来考虑原问题。
字典序严格大于似乎有点烦?考虑小于等于。(其实是我今天想的时候把题意记错了,写完发现过不了样例)
仍然考虑枚举一个长度为i - 1的前缀,然后计算在i脱离限制后的方案数。
下面只考虑长度为i - 1的前缀是合法的情况。
- 如果a_{i}是一个前缀最大值,那么考虑i - 1的前缀最大值是mx,答案加上从(i, mx), (i, mx + 1), \cdots, (i, a_i - 1)开始的方案数。
- 如果a_i不是前缀最大值
- 如果比不是前缀最大值的最小值还大,那么此时前缀i不合法,答案加上从(i, mx)开始的方案书。
- 否则对答案没有贡献。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | /** * loj * Problem#2719 * Accepted * Time: 652ms * Memory: 10236k */ #include <bits/stdc++.h> using namespace std; typedef bool boolean; #define ll long long void exgcd( int a, int b, int & x, int & y) { if (!b) { x = 1, y = 0; } else { exgcd(b, a % b, y, x); y -= (a / b) * x; } } int inv( int a, int n) { int x, y; exgcd(a, n, x, y); return (x < 0) ? (x + n) : (x); } const int Mod = 998244353; template < const int Mod = :: Mod> class Z { public : int v; Z() : v(0) { } Z( int x) : v(x){ } Z(ll x) : v(x % Mod) { } friend Z operator + ( const Z& a, const Z& b) { int x; return Z(((x = a.v + b.v) >= Mod) ? (x - Mod) : (x)); } friend Z operator - ( const Z& a, const Z& b) { int x; return Z(((x = a.v - b.v) < 0) ? (x + Mod) : (x)); } friend Z operator * ( const Z& a, const Z& b) { return Z(a.v * 1ll * b.v); } friend Z operator ~( const Z& a) { return inv(a.v, Mod); } friend Z operator - ( const Z& a) { return Z(0) - a; } Z& operator += (Z b) { return * this = * this + b; } Z& operator -= (Z b) { return * this = * this - b; } Z& operator *= (Z b) { return * this = * this * b; } friend boolean operator == ( const Z& a, const Z& b) { return a.v == b.v; } }; Z<> qpow(Z<> a, int p) { Z<> rt = Z<>(1), pa = a; for ( ; p; p >>= 1, pa = pa * pa) { if (p & 1) { rt = rt * pa; } } return rt; } typedef Z<> Zi; typedef class Input { protected : const static int limit = 65536; FILE * file; int ss, st; char buf[limit]; public : Input():file(NULL) { }; Input( FILE * file):file(file) { } void open( FILE *file) { this ->file = file; } void open( const char * filename) { file = fopen (filename, "r" ); } char pick() { if (ss == st) st = fread (buf, 1, limit, file), ss = 0; //, cerr << "str: " << buf << "ed " << st << endl; return buf[ss++]; } } Input; #define digit(_x) ((_x) >= '0' && (_x) <= '9') Input& operator >> (Input& in, unsigned& u) { char x; while (~(x = in.pick()) && !digit(x)); for (u = x - '0' ; ~(x = in.pick()) && digit(x); u = u * 10 + x - '0' ); return in; } Input& operator >> (Input& in, unsigned long long & u) { char x; while (~(x = in.pick()) && !digit(x)); for (u = x - '0' ; ~(x = in.pick()) && digit(x); u = u * 10 + x - '0' ); return in; } Input& operator >> (Input& in, int & u) { char x; while (~(x = in.pick()) && !digit(x) && x != '-' ); int aflag = ((x == '-' ) ? (x = in.pick(), -1) : (1)); for (u = x - '0' ; ~(x = in.pick()) && digit(x); u = u * 10 + x - '0' ); u *= aflag; return in; } Input& operator >> (Input& in, long long & u) { char x; while (~(x = in.pick()) && !digit(x) && x != '-' ); int aflag = ((x == '-' ) ? (x = in.pick(), -1) : (1)); for (u = x - '0' ; ~(x = in.pick()) && digit(x); u = u * 10 + x - '0' ); u *= aflag; return in; } Input in (stdin); const int N = 6e5 + 5; const int N2 = N << 1; int T, n; Zi fac[N2], _fac[N2]; void init_fac( int l, int r) { for ( int i = l; i <= r; i++) { fac[i] = fac[i - 1] * i; } _fac[r] = ~fac[r]; for ( int i = r; i > l; i--) { _fac[i - 1] = _fac[i] * i; } } void init_fac( int n) { static int old = 0; fac[0] = 1, _fac[0] = 1; if (n > old) { init_fac(old + 1, n); old = n; } } Zi comb( int n, int m) { return (n < m) ? (0) : (fac[n] * _fac[m] * _fac[n - m]); } Zi C( int x, int y) { return comb(x + y, x); } Zi S( int x, int y) { if (y + 1 <= x) return 0; return (y == n) ? (1) : (C(n - x, n - y) - C(n + 1 - x, n - 1 - y)); } boolean vis[N]; int main() { freopen ( "inverse.in" , "r" , stdin); freopen ( "inverse.out" , "w" , stdout); in >> T; while (T--) { in >> n; if (!n) { puts ( "0" ); continue ; } init_fac(n << 1); memset (vis, false , n + 2); int mx = 0, sc = 1, i = 1, a; Zi ans = 0; for (i = 1; i < n; i++) { in >> a; if (a > mx) { for ( int j = mx; j < a; j++) { ans += S(i, j); } mx = a; } else { while (vis[sc]) sc++; if (sc ^ a) { ans += S(i, mx); break ; } } vis[a] = true ; } if (i == n) { in >> a; ans += 1; } else { while (++i <= n) in >> a; } ans = S(0, 0) - ans; printf ( "%d\n" , ans.v); } return 0; } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】博客园携手 AI 驱动开发工具商 Chat2DB 推出联合终身会员
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 聊一聊 C#异步 任务延续的三种底层玩法
· 敏捷开发:如何高效开每日站会
· 为什么 .NET8线程池 容易引发线程饥饿
· golang自带的死锁检测并非银弹
· 如何做好软件架构师
· 欧阳的2024年终总结,迷茫,重生与失业
· 聊一聊 C#异步 任务延续的三种底层玩法
· 上位机能不能替代PLC呢?
· 2024年终总结:5000 Star,10w 下载量,这是我交出的开源答卷
· .NET Core:架构、特性和优势详解
2017-07-10 hdu 1811 Rank of Tetris - 拓扑排序 - 并查集
2017-07-10 hdu 2647 Reward - 拓扑排序
2017-07-10 hdu 3342 Legal or Not - 拓扑排序
2017-07-10 Codeforces 822C Hacker, pack your bags! - 贪心
2016-07-10 Vijos 1308 埃及分数 - 迭代加深
2016-07-10 [搜索]迭代加深
2016-07-10 [复习]深度优先搜索