CF1450H2 Multithreading (Hard Version)
先考虑怎么刻画序列的 \(f\)。
考虑把 w 作为 \(0\),b 作为 \(1\)。
每次我们可以删 00 或 11,最后剩下的 0101... 状物的长度除以 \(4\) 就是 \(f\) 的值。
每次删长度 \(2\) 的串,这对每个位置的奇偶性是不影响的。
考虑把奇数位取反,那么每次可以删 01 或 10,最后剩同色段就是答案。
显然这个同色段长度就是奇数位取反后 0 个数与 1 个数之差。
设 \(u_{0/1}\) 为未知的奇/偶位数量,\(v\) 为已知位权值和。
一个想法是,考虑枚举 \(i\) 和 \(j\) 为 0 在奇偶各选多少个,然后就是一个卷积的形式,可以做到 \(O(n\log n)\)。
另一个想法是,直接枚举剩余位带权和 \(d\),然后设为正的有 \(i\) 个,负的有 \(j\) 个,那么方案数就是 \(\sum\limits_{i-j=d}\dbinom{u_0}{i}\dbinom{u_1}{j}\),范德蒙德卷积做到线性。
H1
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int mod = 998244353;
const int inv2 = (mod + 1) / 2;
void Add(int &x, ll y) { x = (x + y) % mod; }
int Pow(int x, int y) {
int b = x, r = 1;
for(; y; b = (ll)b * b % mod, y /= 2) {
if(y & 1) r = (ll)r * b % mod;
}
return r;
}
const int kN = 2e5 + 5;
int n, q;
string s;
int mul[kN], imul[kN];
void Init(int N = kN - 1) {
mul[0] = 1;
for(int i = 1; i <= N; i++) mul[i] = (ll)mul[i - 1] * i % mod;
imul[N] = Pow(mul[N], mod - 2);
for(int i = N - 1; ~i; i--) imul[i] = (ll)imul[i + 1] * (i + 1) % mod;
}
int C(int n, int m) {
if((n < m) || (m < 0)) return 0;
return (ll)mul[n] * imul[m] % mod * imul[n - m] % mod;
}
int main() {
// freopen("1.in", "r", stdin);
// freopen("1.out", "w", stdout);
ios::sync_with_stdio(0), cin.tie(0);
Init();
cin >> n >> q >> s;
s = " " + s;
int u[2] = {0, 0};
int v = 0;
for(int i = 1; i <= n; i++) {
if(s[i] == '?') u[i & 1]++;
else ((s[i] == 'b') ^ (i & 1)) ? v++ : v--;
}
v = (v + u[0] - u[1]) / 2;
int ans = 0;
for(int d = -n; d <= n; d++) {
if((d & 1) != (v & 1)) continue;
Add(ans, (ll)abs(d - v) * C(u[0] + u[1], u[1] + d));
}
cout << (ll)ans * Pow(inv2, u[0] + u[1]) % mod << "\n";
return 0;
}
我们重新整理一下式子:给定 \(A,B,V\),求 \(\sum\limits_{d\equiv V\pmod 2}|d-V|\dbinom{A+B}{B+d}\)。
考虑枚举 \(k=|d-V|\),则需求 \(\sum\limits_{k\ge 1}2k\left(\dbinom{A+B}{B+V+2k}+\dbinom{A+B}{B+V-2k}\right)\)。
不妨考虑 \(\dbinom{A+B}{B+V-2k}\),前面的同理。
\( \begin{aligned} \sum\limits_{k\ge 1}2k\dbinom{A+B}{B+V-2k} &= (B+V)\sum\limits_{k\ge 1}\dbinom{A+B}{B+V-2k}-\sum\limits_{k\ge 1}(B+V-2k)\dbinom{A+B}{B+V-2k}\\ &= (B+V)\sum\limits_{k\ge 1}\dbinom{A+B}{B+V-2k}-(A+B)\sum\limits_{k\ge 1}\dbinom{A+B-1}{B+V-2k-1} \end{aligned} \)
考虑定义 \(F(A,B,V)=\sum\limits_{k\ge 0}\dbinom{A+B}{B+V-2k}\)。
上式为 \((B+V)F(A,B,V-2)-(A+B)F(A,B-1,V-2)\)。
考虑 \(F\) 怎么求。
\(\sum\limits_{k\ge 0}\left(\dbinom{A+B}{B+V-2k}+\dbinom{A+B}{B+V-2k-1}\right)=\sum\limits_{k\ge 0}\dbinom{A+B}{B+V-k}\) 是可以递推的。
\(\sum\limits_{k\ge 0}\left(\dbinom{A+B}{B+V-2k}-\dbinom{A+B}{B+V-2k-1}\right)=\dbinom{A+B-1}{B+V}\)。
注意到单点改对于 \(A,B,V\) 的修改都是 \(O(1)\) 的,所以直接转移即可。复杂度线性。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int mod = 998244353;
const int inv2 = (mod + 1) / 2;
void Add(int &x, ll y) { x = (x + y) % mod; }
int Pow(int x, int y) {
int b = x, r = 1;
for(; y; b = (ll)b * b % mod, y /= 2) {
if(y & 1) r = (ll)r * b % mod;
}
return r;
}
const int kN = 2e5 + 5;
int n, q;
string s;
int pw2[kN], ipw2[kN], mul[kN], imul[kN];
struct Node {
int A, B, V;
Node() { }
Node(int _A, int _B, int _V) {
A = _A;
B = _B;
V = _V;
}
};
Node qry[kN];
void Init(int N = kN - 1) {
mul[0] = 1;
for(int i = 1; i <= N; i++) mul[i] = (ll)mul[i - 1] * i % mod;
imul[N] = Pow(mul[N], mod - 2);
for(int i = N - 1; ~i; i--) imul[i] = (ll)imul[i + 1] * (i + 1) % mod;
pw2[0] = ipw2[0] = 1;
for(int i = 1; i <= N; i++) {
pw2[i] = 2ll * pw2[i - 1] % mod;
ipw2[i] = (ll)ipw2[i - 1] * inv2 % mod;
}
}
int C(int n, int m) {
if((n < m) || (m < 0)) return 0;
return (ll)mul[n] * imul[m] % mod * imul[n - m] % mod;
}
int cx, cy, cs = 1;
void AddX() { cs = (2ll * cs + mod - C(cx++, cy)) % mod; }
void DelX() { cs = (ll)inv2 * (cs + C(--cx, cy)) % mod; }
void AddY() { Add(cs, C(cx, ++cy)); }
void DelY() { Add(cs, mod - C(cx, cy--)); }
int F(int A, int B, int V) {
int sum = 0;
int x = A + B;
int y = B + V;
while(cx < x) AddX();
while(cx > x) DelX();
while(cy < y) AddY();
while(cy > y) DelY();
return (ll)inv2 * (cs + C(A + B - 1, B + V)) % mod;
}
int Calc(int A, int B, int V) {
int ans = 0;
if(A + B == 1) {
if(((B + V) & 1) && (B + V < 0)) ans++;
if(((B + V) & 1) && (B + V >= 3)) ans--;
}else {
Add(ans, (ll)(A + B) * pw2[A + B - 2]);
Add(ans, (ll)(mod - A - B) * F(A, B - 1, V));
Add(ans, (ll)(mod - A - B) * F(A, B - 1, V - 2));
}
Add(ans, (ll)(mod - B - V) * pw2[A + B - 1]);
Add(ans, (ll)(B + V) * F(A, B, V));
Add(ans, (ll)(B + V) * F(A, B, V - 2));
return ans;
}
int main() {
// freopen("1.in", "r", stdin);
// freopen("1.out", "w", stdout);
ios::sync_with_stdio(0), cin.tie(0);
Init();
cin >> n >> q >> s;
s = " " + s;
int u[2] = {0, 0};
int v = 0;
auto Upd = [&](int x, int c) -> void {
if(s[x] == '?') u[x & 1] += c;
else ((s[x] == 'b') ^ (x & 1)) ? (v += c) : (v -= c);
};
for(int i = 1; i <= n; i++) Upd(i, 1);
qry[0] = Node(u[0], u[1], (v + u[0] - u[1]) / 2);
for(int i = 1; i <= q; i++) {
int x;
char c;
cin >> x >> c;
Upd(x, -1), s[x] = c, Upd(x, 1);
qry[i] = Node(u[0], u[1], (v + u[0] - u[1]) / 2);
}
for(int i = 0; i <= q; i++) {
int A = qry[i].A;
int B = qry[i].B;
int V = qry[i].V;
cout << (ll)Calc(A, B, V) * ipw2[A + B] % mod << "\n";
}
return 0;
}
浙公网安备 33010602011771号