题解:AT_npcapc_2024_d Two Box
drmr
·
·
题解
考虑怎么解决 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;
}
```