fn getline() -> String { let mut ret = String::new(); std::io::stdin().read_line(&mut ret).unwrap(); ret } fn run_length_1(s: &[u8]) -> (usize, Vec) { let n = s.len(); let mut v = vec![]; let mut i = 0; while i < n && s[i] == b'0' { i += 1; } let cnt = i; while i < n { assert!(s[i] == b'1'); i += 1; let mut c = 0; while i < n && s[i] == b'0' { c += 1; i += 1; } v.push(c); } (cnt, v) } /// Verified by https://atcoder.jp/contests/abc198/submissions/21774342 mod mod_int { use std::ops::*; pub trait Mod: Copy { fn m() -> i64; } #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct ModInt { pub x: i64, phantom: ::std::marker::PhantomData } impl ModInt { // x >= 0 pub fn new(x: i64) -> Self { ModInt::new_internal(x % M::m()) } fn new_internal(x: i64) -> Self { ModInt { x: x, phantom: ::std::marker::PhantomData } } pub fn pow(self, mut e: i64) -> Self { debug_assert!(e >= 0); let mut sum = ModInt::new_internal(1); let mut cur = self; while e > 0 { if e % 2 != 0 { sum *= cur; } cur *= cur; e /= 2; } sum } #[allow(dead_code)] pub fn inv(self) -> Self { self.pow(M::m() - 2) } } impl Default for ModInt { fn default() -> Self { Self::new_internal(0) } } impl>> Add for ModInt { type Output = Self; fn add(self, other: T) -> Self { let other = other.into(); let mut sum = self.x + other.x; if sum >= M::m() { sum -= M::m(); } ModInt::new_internal(sum) } } impl>> Sub for ModInt { type Output = Self; fn sub(self, other: T) -> Self { let other = other.into(); let mut sum = self.x - other.x; if sum < 0 { sum += M::m(); } ModInt::new_internal(sum) } } impl>> Mul for ModInt { type Output = Self; fn mul(self, other: T) -> Self { ModInt::new(self.x * other.into().x % M::m()) } } impl>> AddAssign for ModInt { fn add_assign(&mut self, other: T) { *self = *self + other; } } impl>> SubAssign for ModInt { fn sub_assign(&mut self, other: T) { *self = *self - other; } } impl>> MulAssign for ModInt { fn mul_assign(&mut self, other: T) { *self = *self * other; } } impl Neg for ModInt { type Output = Self; fn neg(self) -> Self { ModInt::new(0) - self } } impl ::std::fmt::Display for ModInt { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { self.x.fmt(f) } } impl ::std::fmt::Debug for ModInt { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { let (mut a, mut b, _) = red(self.x, M::m()); if b < 0 { a = -a; b = -b; } write!(f, "{}/{}", a, b) } } impl From for ModInt { fn from(x: i64) -> Self { Self::new(x) } } // Finds the simplest fraction x/y congruent to r mod p. // The return value (x, y, z) satisfies x = y * r + z * p. fn red(r: i64, p: i64) -> (i64, i64, i64) { if r.abs() <= 10000 { return (r, 1, 0); } let mut nxt_r = p % r; let mut q = p / r; if 2 * nxt_r >= r { nxt_r -= r; q += 1; } if 2 * nxt_r <= -r { nxt_r += r; q -= 1; } let (x, z, y) = red(nxt_r, r); (x, y - q * z, z) } } // mod mod_int macro_rules! define_mod { ($struct_name: ident, $modulo: expr) => { #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct $struct_name {} impl mod_int::Mod for $struct_name { fn m() -> i64 { $modulo } } } } const MOD: i64 = 924_844_033; define_mod!(P, MOD); type MInt = mod_int::ModInt

; // Segment Tree. This data structure is useful for fast folding on intervals of an array // whose elements are elements of monoid I. Note that constructing this tree requires the identity // element of I and the operation of I. // Verified by: yukicoder No. 2220 (https://yukicoder.me/submissions/841554) struct SegTree { n: usize, orign: usize, dat: Vec, op: BiOp, e: I, } impl SegTree where BiOp: Fn(I, I) -> I, I: Copy { pub fn new(n_: usize, op: BiOp, e: I) -> Self { let mut n = 1; while n < n_ { n *= 2; } // n is a power of 2 SegTree {n: n, orign: n_, dat: vec![e; 2 * n - 1], op: op, e: e} } // ary[k] <- v pub fn update(&mut self, idx: usize, v: I) { debug_assert!(idx < self.orign); let mut k = idx + self.n - 1; self.dat[k] = v; while k > 0 { k = (k - 1) / 2; self.dat[k] = (self.op)(self.dat[2 * k + 1], self.dat[2 * k + 2]); } } // [a, b) (half-inclusive) // http://proc-cpuinfo.fixstars.com/2017/07/optimize-segment-tree/ #[allow(unused)] pub fn query(&self, rng: std::ops::Range) -> I { let (mut a, mut b) = (rng.start, rng.end); debug_assert!(a <= b); debug_assert!(b <= self.orign); let mut left = self.e; let mut right = self.e; a += self.n - 1; b += self.n - 1; while a < b { if (a & 1) == 0 { left = (self.op)(left, self.dat[a]); } if (b & 1) == 0 { right = (self.op)(self.dat[b - 1], right); } a = a / 2; b = (b - 1) / 2; } (self.op)(left, right) } } // Depends on: datastr/SegTree.rs // Verified by: yukicoder No. 2220 (https://yukicoder.me/submissions/841554) impl SegTree where BiOp: Fn(I, I) -> I, I: Copy { // Port from https://github.com/atcoder/ac-library/blob/master/atcoder/segtree.hpp #[allow(unused)] fn max_right bool>( &self, rng: std::ops::RangeFrom, f: &F, ) -> usize { let mut l = rng.start; assert!(f(self.e)); if l == self.orign { return self.orign; } l += self.n - 1; let mut sm = self.e; loop { while l % 2 == 1 { l = (l - 1) / 2; } if !f((self.op)(sm, self.dat[l])) { while l < self.n - 1 { l = 2 * l + 1; let val = (self.op)(sm, self.dat[l]); if f(val) { sm = val; l += 1; } } return std::cmp::min(self.orign, l + 1 - self.n); } sm = (self.op)(sm, self.dat[l]); l += 1; if (l + 1).is_power_of_two() { break; } } self.orign } // Port from https://github.com/atcoder/ac-library/blob/master/atcoder/segtree.hpp #[allow(unused)] fn min_left bool>( &self, rng: std::ops::RangeTo, f: &F, ) -> usize { let mut r = rng.end; if !f(self.e) { return r + 1; } if r == 0 { return 0; } r += self.n - 1; let mut sm = self.e; loop { r -= 1; while r > 0 && r % 2 == 0 { r = (r - 1) / 2; } if !f((self.op)(self.dat[r], sm)) { while r < self.n - 1 { r = 2 * r + 2; let val = (self.op)(self.dat[r], sm); if f(val) { sm = val; r -= 1; } } return r + 2 - self.n; } sm = (self.op)(self.dat[r], sm); if (r + 1).is_power_of_two() { break; } } 0 } } // https://yukicoder.me/problems/no/1654 (4) // 00 -> 0, ?? -> 1、操作後の文字列は何通り? // 文字列を 0* (10*)* の形に分割し、 10* ごとに DP をする。 // DP の状態は dp[i][x] := i 番目の 10* までで、最後が 10^x であるものが何種類できるか? // -> これだと 1111 のようなケースで破綻しそう。 // 0^a10^{b_0}...0^{b_n}10^c を 0^a'10^{b'_0}...0^{b'_m}10^c' に変換するとみなし、 // a,b,c の条件を探ると、 0<=a'<=a, 0<=c'<=c は自明で、b については大きさ m のマッチングがあればよい。 // そのマッチングでは b_{k[i]} >= b'_i が成り立つべきである。 // 大きさ m のマッチングがあるような b' を探るために、貪欲法でマッチングを解くことを考える。 // 0 <= i < j < n に対して i の次にマッチングされる頂点が j であることと、 // max b[i + 1..j] < (次の値) and b[j] >= (次の値) が同値。 // sum b[i] <= 3 * 10^6 であることからこれに O(b[j]) 時間掛けて良いことに注意すると、 // 0 <= x <= b[j] なる x のそれぞれに対して min {i | max b[i + 1..j] < x} を二分探索すればよい。 // Tags: run-length-encoding, matching, operations-on-sequences, operations-on-strings fn main() { let s = getline().trim().as_bytes().to_vec(); let (first0, mut middle) = run_length_1(&s); if middle.is_empty() { println!("{first0}"); return; } let last0 = middle.pop().unwrap(); let n = middle.len(); let mut st = SegTree::new(n + 1, |a, b| a.max(b), 0); st.update(0, 1usize << 40); for i in 0..n { st.update(i + 1, middle[i]); } let mut st_sum = SegTree::new(n + 1, |a, b| a + b, MInt::new(0)); st_sum.update(0, MInt::new(1)); for i in 0..n { for x in 0..=middle[i] { let j = if x == 0 { i + 1 } else { st.min_left(..i + 1, &|v| v < x) }; let val = st_sum.query(j - 1..i + 1); let prev = st_sum.query(i + 1..i + 2); st_sum.update(i + 1, val + prev); } } println!("{}", st_sum.query(0..n + 1) * (first0 as i64 + 1) * (last0 as i64 + 1)); }