题解:AT_npcapc_2024_d Two Box

· · 题解

考虑怎么解决 Q = 1 的问题。

按照编号从大到小的顺序,依次确定每个球的行为。对于球 k,他仅能出现在 A_i \ge k 的位置。

取出所有的 A_i \ge k 的位置,它们构成了若干极长连续段。则对于每一段 [l, r], r \ne n 来说,球必须在 [l, r + \bold{1}] 的操作内操作偶数次。当然,若 r = n 则无限制。

对于所有的 k 生成的连续段集合拥有类似树的性质。其中当 k = 1 时仅存在一个连续段 [1, n],作为树根。对于 k + 1 生成的连续段,向 k 生成的唯一包含它的连续段连边。

dp。对于第 k 层的其中一个连续段,考虑记 f_0, f_1, \cdots, f_d。f_x 表示:选完了 \ge k 的球所占有的操作后,在该连续段中仍剩 f_x 次操作。同样的,g 表示选完了 \ge k 的球所占有的操作后,在当前连续段中仍剩 g_x 次操作。

$$ f_i = \sum_{j \ge i, j \equiv i (\text{mod } 2)} g_j \binom{j}{i} $$ ,当然,如果连续段的 $r = n$,需要去掉偶数的限制。 生成函数,那么 $f(x) = \frac{g(x + 1) + g(x - 1)}{2}$。若去掉偶数限制,则 $f(x) = g(x + 1)$。观察最终的答案,想求出根节点没有剩下操作的方案数,即 $[x^0]f(x) = f(0)$。 观察到第 $0$ 层(根)仅需 $f(0)$,而 $f(0)$ 又只和第 $1$ 层的 $g(-1), g(0), g(1)$ 有关。那么,对于第 $i$ 层来说,只需要维护 $f$ 在 $[-i + 1, i - 1]$ 之中的所有点值即可。从高层向低层计算点值即可。 考虑修改,当我们修改一个元素 $a_x$ 的值时,受到影响的区间一定包含位置 $x$,于是,受到影响的区间仅 $O(m)$ 个。在本题中,我们先从低到高删去原有的区间,再加入新的区间。原先 dp 需要计算所有儿子的值之乘积,此处可以简单使用 $O(M^2)$ 个树状数组维护(注意为了实现删除操作要阔域)。 复杂度 $O((nm + q) m^2 \log n)$。我的代码写的很笨蛋。 ```cpp #include <bits/stdc++.h> #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize("unroll-loops") #pragma GCC optimize("Ofast") #define ll long long using namespace std; #define FOR(x, y, z) for(int (x) = (y); (x) <= (z); (x)++) #define ROF(x, y, z) for(int (x) = (y); (x) >= (z); (x)--) #define mp make_pair #define pb push_back const ll Mod = 998244353; const ll inv2 = (Mod + 1) / 2; const int N = 3e4 + 10; int n, m, q, a[N]; ll F[1000]; ll *f = F + 500; ll PW[35][N]; ll (*pw)[N] = PW + 15; set<pair<int, int> > st[20]; ll qpow(ll x, ll y){ll r = 1; while(y){if(y & 1) r = r * x % Mod; x = x * x % Mod; y >>= 1;} return r;} struct bit{ ll a[N], b[N]; bit(){FOR(i, 0, N - 1) a[i] = 1, b[i] = 0;} void Add(ll x, ll y){ for(; x <= n; x += (x & -x)) a[x] = a[x] * y % Mod; return ; } void AddZero(ll x, ll y){ for(; x <= n; x += (x & -x)) b[x] += y; return ; } pair<ll, ll> Query(ll x){ ll r = 1, k = 0; for(; x; x -= (x & -x)) r = r * a[x] % Mod, k += b[x]; return mp(k, r); } ll QuerySeg(ll l, ll r){ auto tmp = Query(r); auto tmp2 = Query(l - 1); if(tmp2.first == tmp.first) return tmp.second * qpow(tmp2.second, Mod - 2) % Mod; return 0; } }TR[35][16]; bit (*tr)[16] = TR + 15; struct BIT_{ int a[N]; void Add(int x, int y){ for(; x <= n; x += (x & -x)) a[x] += y; return ; } int Query(int x){ int r = 0; for(; x; x -= (x & -x)) r += a[x]; return r; } }BIT[16]; void Add(int h, int l, int r, int op){ int flg = (r == n); if(r != n) r++; int vl = 1 - h, vr = h - 1; int tot = BIT[h].Query(r) - BIT[h].Query(l - 1); if(h == m){ FOR(v, vl - 1, vr + 1) f[v] = pw[v][tot]; } else{ FOR(v, vl - 1, vr + 1) f[v] = pw[v][tot] * tr[v][h + 1].QuerySeg(l, r) % Mod; } FOR(v, vl, vr){ ll tmp; if(!flg) tmp = (f[v + 1] + f[v - 1]) * inv2 % Mod; else tmp = f[v + 1]; if(tmp) tr[v][h].Add(l, (op == 1) ? tmp : qpow(tmp, Mod - 2)); else tr[v][h].AddZero(l, op); } return ; } signed main(){ ios::sync_with_stdio(false); cin.tie(0), cout.tie(0); cin >> n >> m >> q; FOR(i, 1, n) cin >> a[i]; FOR(j, -15, 15){pw[j][0] = 1; FOR(i, 1, n) pw[j][i] = pw[j][i - 1] * (j + Mod) % Mod;} FOR(i, 1, n) BIT[max(a[i], a[i - 1])].Add(i, 1); ROF(i, m, 1){ ll lst = -1; FOR(j, 1, n + 1){ if(a[j] >= i){if(lst == -1) lst = j;} else if(lst != -1){ Add(i, lst, j - 1, 1); st[i].insert(mp(lst, j - 1)); lst = -1; } } st[i].insert(mp(-1e9, -1e9)); st[i].insert(mp(1e9, 1e9)); } while(q--){ int x, y, tmp; cin >> x >> y; tmp = max(a[x], y); vector<tuple<int, int, int> > vec1, vec2; if(a[x] < y){ FOR(i, 1, a[x]){ auto it = st[i].upper_bound(mp(x, 1e9)); auto seg1 = *prev(it); if(seg1.first <= x && x <= seg1.second){ vec1.pb(make_tuple(i, seg1.first, seg1.second)); vec2.pb(make_tuple(i, seg1.first, seg1.second)); } } FOR(i, a[x] + 1, y){ auto it = st[i].upper_bound(mp(x, 1e9)); auto seg1 = *prev(it), seg2 = *it; if(seg1.second < x - 1 && seg2.first > x + 1){ st[i].insert(mp(x, x)); vec2.pb(make_tuple(i, x, x)); } else if(seg1.second == x - 1 && seg2.first > x + 1){ st[i].erase(prev(it)); st[i].insert(mp(seg1.first, x)); vec1.pb(make_tuple(i, seg1.first, seg1.second)); vec2.pb(make_tuple(i, seg1.first, x)); } else if(seg1.second < x - 1 && seg2.first == x + 1){ st[i].erase(it); st[i].insert(mp(x, seg2.second)); vec1.pb(make_tuple(i, seg2.first, seg2.second)); vec2.pb(make_tuple(i, x, seg2.second)); } else{ st[i].erase(prev(it)), st[i].erase(seg2); st[i].insert(mp(seg1.first, seg2.second)); vec1.pb(make_tuple(i, seg1.first, seg1.second)); vec1.pb(make_tuple(i, seg2.first, seg2.second)); vec2.pb(make_tuple(i, seg1.first, seg2.second)); } } } if(a[x] > y){ FOR(i, 1, y){ auto it = st[i].upper_bound(mp(x, 1e9)); auto seg1 = *prev(it); if(seg1.first <= x && x <= seg1.second){ vec1.pb(make_tuple(i, seg1.first, seg1.second)); vec2.pb(make_tuple(i, seg1.first, seg1.second)); } } FOR(i, y + 1, a[x]){ auto it = st[i].upper_bound(mp(x, 1e9)); auto seg1 = *prev(it); if(seg1.first <= x && x <= seg1.second){ st[i].erase(prev(it)); vec1.pb(make_tuple(i, seg1.first, seg1.second)); if(seg1.first < x) st[i].insert(mp(seg1.first, x - 1)), vec2.pb(make_tuple(i, seg1.first, x - 1)); if(x < seg1.second) st[i].insert(mp(x + 1, seg1.second)), vec2.pb(make_tuple(i, x + 1, seg1.second)); } } } for(auto i : vec1) Add(get<0>(i), get<1>(i), get<2>(i), -1); BIT[max(a[x], a[x - 1])].Add(x, -1); if(x + 1 <= n) BIT[max(a[x + 1], a[x])].Add(x + 1, -1); a[x] = y; BIT[max(a[x], a[x - 1])].Add(x, 1); if(x + 1 <= n) BIT[max(a[x + 1], a[x])].Add(x + 1, 1); reverse(vec2.begin(), vec2.end()); for(auto i : vec2) Add(get<0>(i), get<1>(i), get<2>(i), 1); cout << tr[0][1].QuerySeg(1, 1) << "\n"; } return 0; } ```