[CF] H. Bro Thinks He's Him - Codeforces Round 1003 (Div. 4)

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;
}
Prev: [CF] F. Topforces Strikes Back - Codeforces Round 570 (Div. 3)
Next: [CF] D. Cubes - Codeforces Round 295 (Div. 2)