https://codeforces.com/contest/2065/problem/H
题目大意
给出一个 $01$ 字符串 $s$ 和 $q$ 次询问,每次询问将 $v_i$ 位置的字符翻转(询问不独立),之后询问这个串由下述函数算出的值是多少。
$f(S)$ 表示 $S$ 由多少个连续的相同字符的段,比如 $00110001$ 有 $00, 11, 000, 1$ 这样的 $4$ 段。
$g(S)$ 表示对于 $S$ 的所有的非空子序列 $T$ 的 $f(T)$ 的和。
求每次修改字符后的 $g(S)$ 的值。
$1 \le |S|, q \le 2 \times 10^5$。$1 \le v_i \le |S|$。
简要题解
观察:段数等于 $01$ 分界位置加 $1$。(加 $1$ 这部分好说,就是 $2 ^{|S|} - 1$。)
因此实际上我们可以把原问题转化为 $01$ 分界的贡献。
考虑 $i$ 位置为 $0$ 则当且仅当其子序列 $T$ 前一位或者后一位是 $1$ 才会产生贡献。
于是我们可以枚举所有的 $1$ 然后我们发现我们并不关心 $1$ 前面的选法和 $0$ 后面的选法,于是
$$ val = \sum_{j = 0}^{i - 1} 2 ^ {j} \cdot 2 ^ {n - i - 1} \cdot [s[j] = '1'] $$这里我们注意到很容易把 $j$ 的部分提出来。
$$ val = \left\(\sum_{j = 0}^{i - 1} 2 ^ {j} \cdot [s[j] = '1'] \right\) \cdot 2 ^ {n - i - 1} $$因此我们只需要一个能快速求子段和,快速单点修改的数据结构就可以处理 $j$ 的和了。
右边的情况是对称的。因为 $01$ 要分开处理,左右要分开处理,于是直接开 $4$ 个 BIT 就好了。
每次变化只要取消之前的贡献,增加新的贡献即可。
复杂度
$T$:$O(n \log n)$
$S$:$O(n)$
代码实现
#include <bits/stdc++.h>
using namespace std;
int io_=[](){ ios::sync_with_stdio(false); cin.tie(nullptr); return 0; }();
using LL = long long;
using ULL = unsigned long long;
using LD = long double;
using PII = pair<int, int>;
using VI = vector<int>;
using MII = map<int, int>;
template<typename T> void cmin(T &x,const T &y) { if(y<x) x=y; }
template<typename T> void cmax(T &x,const T &y) { if(x<y) x=y; }
template<typename T> bool ckmin(T &x,const T &y) {
return y<x ? (x=y, true) : false; }
template<typename T> bool ckmax(T &x,const T &y) {
return x<y ? (x=y, true) : false; }
template<typename T> void cmin(T &x,T &y,const T &z) {// x<=y<=z
if(z<x) { y=x; x=z; } else if(z<y) y=z; }
template<typename T> void cmax(T &x,T &y,const T &z) {// x>=y>=z
if(x<z) { y=x; x=z; } else if(y<z) y=z; }
// mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
// mt19937_64 rnd_64(chrono::system_clock::now().time_since_epoch().count());
template<long long Mo=998244353> struct ModInt {
static long long MO;
static void setMo(long long mo) { MO = mo; }
long long x;
ModInt(long long x=0) : x(x){ norm(); }
friend istream &operator>>(istream& in, ModInt &B) { in>>B.x; return in; }
friend ostream &operator<<(ostream& out, const ModInt &B) {
out<<B.x; return out; }
// ModInt operator=(int x_) { x=x_; norm(); return *this; }
void norm() { x = (x%MO + MO) % MO; }
long long get() { return x; }
ModInt operator-() const { return ModInt(MO - x); }
ModInt operator+=(const ModInt &B) { x+=B.x; if(x>=MO) x-=MO; return *this; }
ModInt operator-=(const ModInt &B) { x-=B.x; if(x<0) x+=MO; return *this; }
ModInt operator*=(const ModInt &B) { x=x*B.x%MO; return *this; }
ModInt operator+(const ModInt &B) const { ModInt ans=*this; return ans+=B; }
ModInt operator-(const ModInt &B) const { ModInt ans=*this; return ans-=B; }
ModInt operator*(const ModInt &B) const { ModInt ans=*this; return ans*=B; }
ModInt operator^(long long n) const {
ModInt a=*this; ModInt ans(1);
while(n) { if(n&1) ans*=a; a*=a; n>>=1; }
return ans;
}
ModInt inv() const { return (*this)^(MO-2); } // if MO is prime
ModInt operator/=(const ModInt &B) { (*this)*=B.inv(); return *this; }
ModInt operator/(const ModInt &B) const { ModInt ans=*this; return ans/=B; }
bool operator<(const ModInt &B) const { return x<B.x; }
bool operator==(const ModInt &B) const { return x==B.x; }
bool operator!=(const ModInt &B) const { return x!=B.x; }
};
template<long long Mo> long long ModInt<Mo>::MO = Mo;
typedef ModInt<998244353> Mint;
// typedef ModInt<1'000'000'007> Mint;
template<typename T> struct GetZero { T operator()() const { return T(0); } };
template<typename T,
typename OpPlus=plus<T>,typename OpMinus=minus<T>,
typename Zero=GetZero<T> >
struct BIT {
static int lowbit(int x) { return x&(-x); }
constexpr static OpPlus opp{};
constexpr static OpMinus opm{};
constexpr static Zero zero{};
int n;
vector<T> tree; // tree[i] -> sum of [i-lowbit(i)+1,i]
BIT(int n_=0):n(n_),tree(n+1,zero()) {}
void init(int n_) { n=n_; tree.assign(n+1,zero()); }
void init(const vector<T> &vec) { // v[0 ~ n_-1]
n=vec.size();
vector<T> tmp(n+1,zero());
for(int i=1;i<=n;i++) tmp[i]=opp(tmp[i-1],vec[i-1]);
for(int i=1;i<=n;i++) tree[i]=opm(tmp[i],tmp[i-lowbit(i)]);
}
void add(int p,T v) {
for(;p<=n;p+=lowbit(p)) tree[p]=opp(tree[p],v);
}
T sum(int p) {
T ans=zero();
for(;p;p-=lowbit(p)) ans=opp(ans,tree[p]);
return ans;
}
T sum(int l,int r) { return opm(sum(r),sum(l-1)); }
};
/*
---------1---------2---------3---------4---------5---------6---------7---------
1234567890123456789012345678901234567890123456789012345678901234567890123456789
*/
const int M = 2e5 + 5;
vector<Mint> pw2;
void init() {
pw2.assign(M, 1);
for (int i = 1; i < M; i++) {
pw2[i] = pw2[i - 1] * 2;
}
}
void solve() {
string s; cin >> s;
int n = s.length();
vector<BIT<Mint>> bit(4, BIT<Mint>(n));
Mint ans = 0;
for (int i = 0; i < n; i++) {
int v = s[i] - '0';
bit[v << 1].add(i + 1, pw2[i]);
bit[v << 1 | 1].add(i + 1, pw2[n - i - 1]);
}
for (int i = 1; i < n; i++) {
int v = (s[i] - '0') ^ 1;
ans += bit[v << 1].sum(i) * pw2[n - i - 1];
}
ans += pw2[n] - 1;
// cerr << ans << '\n';
int q; cin >> q;
int vi;
for (int i = 0; i < q; i++) {
cin >> vi; vi--;
int v = s[vi] - '0';
if (vi) ans -= bit[(v ^ 1) << 1].sum(vi) * pw2[n - vi - 1];
if (vi + 1 < n) ans -= bit[(v ^ 1) << 1 | 1].sum(vi + 1, n) * pw2[vi];
bit[v << 1].add(vi + 1, -pw2[vi]);
bit[v << 1 | 1].add(vi + 1, -pw2[n - vi - 1]);
if (vi) ans += bit[v << 1].sum(vi) * pw2[n - vi - 1];
if (vi + 1 < n) ans += bit[v << 1 | 1].sum(vi + 1, n) * pw2[vi];
bit[(v ^ 1) << 1].add(vi + 1, pw2[vi]);
bit[(v ^ 1) << 1 | 1].add(vi + 1, pw2[n - vi - 1]);
if (s[vi] == '1') s[vi] = '0';
else s[vi] = '1';
cout << ans << (" \n"[i == q - 1]);
}
}
int main() {
init();
int t = 1;
cin >> t;
while (t--) {
solve();
}
return 0;
}
Next: [CF] D. Cubes - Codeforces Round 295 (Div. 2)