Problem:
Score : 1100 points

Problem Statement

We will call a string that can be obtained by concatenating two equal strings an even string.
For example, xyzxyz and aaaaaa are even, while ababab and xyzxy are not.

For a non-empty string S, we will define f(S) as the shortest even string that can be obtained by appending one or more characters to the end of S.
For example, f(abaaba)=abaababaab.
It can be shown that f(S) is uniquely determined for a non-empty string S.

You are given an even string S consisting of lowercase English letters.
For each letter in the lowercase English alphabet, find the number of its occurrences from the l-th character through the r-th character of f^{10^{100}} (S).

Here, f^{10^{100}} (S) is the string f(f(f( ... f(S) ... ))) obtained by applying f to S 10^{100} times.

Constraints

2 \leq |S| \leq 2\times 10^5

1 \leq l \leq r \leq 10^{18}

S is an even string consisting of lowercase English letters.

l and r are integers.

Input

Input is given from Standard Input in the following format:

S
l r

Output

Print 26 integers in a line with spaces in between.
The i-th integer should be the number of the occurrences of the i-th letter in the lowercase English alphabet from the l-th character through the r-th character of f^{10^{100}} (S).

Sample Input 1

abaaba
6 10

Sample Output 1

3 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Since f(abaaba)=abaababaab, the first ten characters in f^{10^{100}}(S) is also abaababaab. Thus, the sixth through the tenth characters are abaab. In this string, a appears three times, b appears twice and no other letters appear, and thus the output should be 3 and 2 followed by twenty-four 0s.

Sample Input 2

xx
1 1000000000000000000

Sample Output 2

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1000000000000000000 0 0

Sample Input 3

vgxgpuamkvgxgvgxgpuamkvgxg
1 1000000000000000000

Sample Output 3

87167725689669676 0 0 0 0 0 282080685775825810 0 0 0 87167725689669676 0 87167725689669676 0 0 87167725689669676 0 0 0 0 87167725689669676 141040342887912905 0 141040342887912905 0 0

Solution in Rust (1.42.0) (judge verdict: Wrong Answer)

use proconio::input;
// ordtools {{{
#[allow(dead_code)]
mod ordtools {
    pub trait Ordtools: PartialOrd + Clone + Sized {
        fn change_min(&mut self, rhs: &Self) {
            if rhs < self {
                *self = rhs.clone();
            }
        }

        fn change_max(&mut self, rhs: &Self) {
            if rhs > self {
                *self = rhs.clone();
            }
        }
    }

    impl<T: PartialOrd + Clone + Sized> Ordtools for T {}
}
// }}}
// rmq {{{
#[allow(dead_code)]
mod rmq {
    use super::ordtools::Ordtools;
    use std::ops::{Bound, Range, RangeBounds};

    // TODO: クレートを分けます。
    trait BitPosition {
        fn pow_of_two(self) -> usize;
    }

    impl BitPosition for usize {
        fn pow_of_two(self) -> usize {
            1 << self
        }
    }

    trait Bit {
        fn flip(self) -> Self;
        fn reverse_and_flip(self) -> Self;
        fn lg_unchecked(self) -> u32;
        fn lg_usize_unchecked(self) -> usize;
        fn lg(self) -> Option<u32>;
        fn lg_usize(self) -> Option<usize>;
        fn lg_ceil(self) -> u32;
        fn lg_ceil_usize(self) -> usize;
    }

    impl Bit for usize {
        fn flip(self) -> Self {
            self ^ std::usize::MAX
        }
        fn reverse_and_flip(self) -> Self {
            self.reverse_bits() ^ std::usize::MAX
        }
        fn lg_ceil(self) -> u32 {
            self.next_power_of_two().trailing_zeros()
        }
        fn lg_ceil_usize(self) -> usize {
            self.lg_ceil() as usize
        }
        fn lg_unchecked(self) -> u32 {
            (self + 1).lg_ceil() - 1
        }
        fn lg_usize_unchecked(self) -> usize {
            self.lg_unchecked() as usize
        }
        fn lg(self) -> Option<u32> {
            if self == 0 {
                None
            } else {
                Some(self.lg_unchecked())
            }
        }
        fn lg_usize(self) -> Option<usize> {
            if self == 0 {
                None
            } else {
                Some(self.lg_usize_unchecked())
            }
        }
    }

    pub struct FastMinimum {
        lca: Box<LeastCommonAncestor>,
    }
    impl FastMinimum {
        pub fn build<T: Ord>(seq: &[T]) -> Self {
            assert!(!seq.is_empty());
            let parent = construct_cartesian_tree(seq);
            let mut tree = vec![vec![]; seq.len()];
            let mut root = 0;
            for (i, &p) in parent.iter().enumerate() {
                if i == p {
                    root = i;
                } else {
                    tree[i].push(p);
                    tree[p].push(i);
                }
            }
            Self {
                lca: Box::new(LeastCommonAncestor::from_tree(root, &tree)),
            }
        }

        pub fn query(&self, range: impl RangeBounds<usize>) -> Option<usize> {
            let start = match range.start_bound() {
                Bound::Excluded(&x) => x + 1,
                Bound::Included(&x) => x,
                Bound::Unbounded => 0,
            };
            let end = match range.end_bound() {
                Bound::Excluded(&x) => {
                    if x == 0 {
                        return None;
                    } else {
                        x - 1
                    }
                }
                Bound::Included(&x) => x,
                Bound::Unbounded => self.lca.vertex_count() - 1,
            };
            if start > end {
                None
            } else {
                Some(self.lca.query(start, end))
            }
        }

        pub fn query_nonempty(&self, range: impl RangeBounds<usize>) -> usize {
            let start = match range.start_bound() {
                Bound::Excluded(&x) => x + 1,
                Bound::Included(&x) => x,
                Bound::Unbounded => 0,
            };
            let end = match range.end_bound() {
                Bound::Excluded(&x) => {
                    assert!(x != 0);
                    x - 1
                }
                Bound::Included(&x) => x,
                Bound::Unbounded => self.lca.vertex_count() - 1,
            };
            assert!(start <= end);
            self.lca.query(start, end)
        }
    }

    pub fn construct_cartesian_tree<T: Ord>(seq: &[T]) -> Vec<usize> {
        let mut p = vec![0; seq.len()];
        let mut stack = Vec::with_capacity(seq.len());
        stack.push(0);
        for x in 1..seq.len() {
            if let Some((j, y)) = stack
                .iter()
                .copied()
                .enumerate()
                .rfind(|&(_, y)| seq[y] <= seq[x])
            {
                p[x] = y;
                if j != stack.len() - 1 {
                    let z = stack[j + 1];
                    p[z] = x;
                }
                stack.truncate(j + 1);
                stack.push(x);
            } else {
                p[stack[0]] = x;
                p[x] = x;
                stack = vec![x];
            }
        }
        p
    }

    #[derive(Debug, Clone, Eq, PartialEq)]
    pub struct LeastCommonAncestor {
        span: Vec<Range<usize>>,
        time_to_id: Vec<usize>,
        compound_table: CompoundTable,
    }

    impl LeastCommonAncestor {
        pub fn vertex_count(&self) -> usize {
            self.span.len()
        }

        pub fn from_tree(root: usize, tree: &[Vec<usize>]) -> Self {
            // dfs に渡したい環境変数を束ねます。
            #[derive(Debug, Eq, PartialEq)]
            struct Env<'a> {
                time: usize,
                time_to_id: Vec<usize>,
                span: Vec<Range<usize>>,
                depth_table: Vec<usize>,
                tree: &'a [Vec<usize>],
            }
            let mut env = Env {
                time: 0,
                time_to_id: vec![0; tree.len() * 2 - 1],
                depth_table: vec![0; tree.len() * 2 - 1],
                span: vec![tree.len() * 2 - 1..0; tree.len()],
                tree,
            };

            fn dfs(x: usize, p: usize, d: usize, env: &mut Env) {
                env.time_to_id[env.time] = x;
                env.depth_table[env.time] = d;
                env.span[x].start.change_min(&env.time);
                env.time += 1;

                for y in env.tree[x].iter().copied().filter(|&y| y != p) {
                    dfs(y, x, d + 1, env);
                    env.time_to_id[env.time] = x;
                    env.depth_table[env.time] = d;
                    env.time += 1;
                }
                env.span[x].end.change_max(&(env.time));
            }
            dfs(root, root, 0, &mut env);

            Self {
                span: env.span,
                time_to_id: env.time_to_id,
                compound_table: CompoundTable::from_vec(env.depth_table),
            }
        }

        pub fn query(&self, u: usize, v: usize) -> usize {
            let Range {
                start: start_u,
                end: end_u,
            } = self.span[u];
            let Range {
                start: start_v,
                end: end_v,
            } = self.span[v];
            self.time_to_id[self
                .compound_table
                .query_nonempty(start_u.min(start_v)..end_u.max(end_v))]
        }
    }

    #[derive(Debug, Clone, Eq, PartialEq)]
    pub struct CompoundTable {
        seq: Vec<usize>,
        block_size: usize,
        pattern: Vec<usize>,
        encyclopedia: Encyclopedia,
        sparse_table: SparseTable<usize>,
    }
    impl CompoundTable {
        #[inline]
        pub fn from_vec(seq: Vec<usize>) -> Self {
            let block_size = seq
                .len()
                .lg_usize()
                .map(|x| ((x as f64) * 0.65) as usize)
                .unwrap_or(1)
                .max(1);
            Self::from_vec_with_block_size(seq, block_size)
        }

        pub fn from_vec_with_block_size(seq: Vec<usize>, block_size: usize) -> Self {
            assert!(block_size <= seq.len());
            assert!(!seq.is_empty());
            assert!(
                (0..seq.len() - 1).all(|i| seq[i] + 1 == seq[i + 1] || seq[i] == seq[i + 1] + 1)
            );

            // ブロックごとのパターンを計算です。
            let mut pattern = vec![0; (seq.len() + block_size - 1) / block_size];
            for (i, x) in pattern.iter_mut().enumerate() {
                let mut coeff = 1;
                for j in block_size * i + 1..(block_size * (i + 1)).min(seq.len()) {
                    if seq[j - 1] > seq[j] {
                        *x += coeff;
                    }
                    coeff += coeff;
                }
            }
            let encyclopedia = Encyclopedia::with_len(block_size);
            let sparse_table = SparseTable::from_vec(
                pattern
                    .iter()
                    .copied()
                    .enumerate()
                    .map(|(i, seq_id)| {
                        seq[block_size * i + encyclopedia.query_nonempty(seq_id, 0..block_size)]
                    })
                    .collect(),
            );

            Self {
                block_size,
                seq,
                pattern,
                encyclopedia,
                sparse_table,
            }
        }

        #[inline]
        pub fn query(&self, range: Range<usize>) -> Option<usize> {
            if range.start >= range.end {
                None
            } else {
                Some(self.query_nonempty(range))
            }
        }

        pub fn query_nonempty(&self, range: Range<usize>) -> usize {
            let Range { start, end } = range;
            assert!(start < end);
            let k = self.block_size;
            let start_block = start / k;
            let start_rem = start - start_block * k;
            let end_block = end / k;
            let end_rem = end - end_block * k;
            if start_block == end_block {
                start_block * self.block_size
                    + self
                        .encyclopedia
                        .query_nonempty(self.pattern[start_rem], start_rem..end_rem)
            } else {
                let left = self
                    .encyclopedia
                    .query(self.pattern[start_block], start_rem..self.block_size)
                    .map(|i| start_block * self.block_size + i);
                let center =
                    self.sparse_table
                        .query(start_block + 1..end_block)
                        .map(|central_block| {
                            central_block * self.block_size
                                + self
                                    .encyclopedia
                                    .query_nonempty(self.pattern[central_block], 0..self.block_size)
                        });
                let right = self
                    .pattern
                    .get(end_block)
                    .and_then(|&pattern| self.encyclopedia.query(pattern, 0..end_rem))
                    .map(|i| end_block * self.block_size + i);
                [left, center, right]
                    .iter()
                    .flatten()
                    .copied()
                    .min_by_key(|&i| self.seq[i]) // std::cmp::min は同点の場合 first が優先です。
                    .unwrap()
            }
        }
    }

    #[derive(Debug, Clone, Eq, PartialEq)]
    pub struct SparseTable<T: Ord + std::fmt::Debug> {
        pub seq: Vec<T>,
        table: Vec<Vec<usize>>,
    }

    impl<T: Ord + std::fmt::Debug> SparseTable<T> {
        pub fn from_vec(seq: Vec<T>) -> Self {
            let n = seq.len();
            let h = n.lg_usize().unwrap_or(0) + 1;
            let mut table = vec![vec![0; n]; h];
            table[0] = (0..n).collect();
            let mut d = 1;
            for i in 1..h {
                let (left, right) = table.split_at_mut(i);
                let crr = &mut right[0];
                crr.copy_from_slice(&left[i - 1]);
                for j in d..seq.len() {
                    if seq[crr[j - d]] > seq[crr[j]] {
                        crr[j - d] = crr[j];
                    }
                }
                d += d;
            }
            Self { table, seq }
        }

        #[inline]
        pub fn query(&self, range: Range<usize>) -> Option<usize> {
            if range.start >= range.end {
                None
            } else {
                Some(self.query_nonempty(range))
            }
        }

        pub fn query_nonempty(&self, range: Range<usize>) -> usize {
            let Range { start, end } = range;
            assert!(start < end);
            let d = match end - start {
                1 => 1,
                _ => ((end - start).next_power_of_two() as usize) / 2,
            };
            assert!(d <= end - start && end - start <= 2 * d);
            let row = &self.table[d.trailing_zeros() as usize];
            let mut ans = row[start];
            if let Some(&x) = row.get(end - d) {
                // ans < x は保証されています。
                if self.seq[ans] > self.seq[x] {
                    ans = x;
                }
            }
            ans
        }
    }

    #[derive(Debug, Clone, Eq, PartialEq)]
    pub struct Encyclopedia {
        len: usize,
        table: Vec<Vec<usize>>,
    }

    impl Encyclopedia {
        pub fn with_len(len: usize) -> Self {
            Self {
                len,
                table: if len == 0 {
                    vec![vec![]]
                } else {
                    let mut ans = vec![vec![0; len]; (len - 1).pow_of_two()];
                    let mut a: Vec<usize> = (0..len).collect();
                    for ans in ans.iter_mut() {
                        // 累積 min-position を計算していきます。
                        ans[0] = 0;
                        for i in 1..len {
                            let j = ans[i - 1];
                            ans[i] = if a[j] <= a[i] { j } else { i };
                        }

                        // a を次のイテレーションで使うものに変えます。
                        // もっとも左の Pos を Neg に変えて、それより前をすべて Pos に変えます。
                        if let Some(s) = (0..len - 1).find(|&i| a[i] < a[i + 1]) {
                            a[s] = a[s + 1] + 1;
                            (0..s).rev().for_each(|i| a[i] = a[i + 1] - 1);
                        }
                    }
                    ans
                },
            }
        }

        #[inline]
        pub fn query(&self, seq_id: usize, range: Range<usize>) -> Option<usize> {
            if range.start >= range.end {
                None
            } else {
                Some(self.query_nonempty(seq_id, range))
            }
        }

        pub fn query_nonempty(&self, seq_id: usize, range: Range<usize>) -> usize {
            let Range { start, end } = range;
            assert!(start < end);
            start + self.table[seq_id >> start][end - start - 1]
        }
    }

    pub fn construct_seq_from_seq_id(len: usize, seq_id: usize) -> Vec<usize> {
        assert!(seq_id < len.pow_of_two());
        let mut ans = vec![2 * len; len]; // あとで調整するので、とりあえず大きめの値にしておきます。`
        let mut x = seq_id;
        for i in 0..len - 1 {
            ans[i + 1] = if x % 2 == 0 { ans[i] + 1 } else { ans[i] - 1 };
            x /= 2;
        }
        let diff = ans[len - 1] - (len - 1);
        ans.iter_mut().for_each(|x| *x -= diff);
        ans
    }
}
// }}}
// suffix_array {{{
#[allow(dead_code)]
mod suffix_array {
    pub fn suffix_array<T: Ord>(s: &[T]) -> Vec<usize> {
        let n = s.len();
        let mut ord: Vec<usize> = (0..n).collect();
        ord.sort_by_key(|&i| &s[i]);
        let mut cmp = vec![0; n];
        for i in 1..n {
            cmp[i] = if s[ord[i - 1]] == s[ord[i]] {
                cmp[i - 1]
            } else {
                cmp[i - 1] + 1
            };
        }
        for d in std::iter::successors(Some(1), |x| Some(x * 2)).take_while(|&x| x <= n) {
            let mut ord_inverse = vec![0; n];
            (0..n).for_each(|i| ord_inverse[ord[i]] = i);
            let cmp_count = *cmp.last().unwrap() + 1;
            let mut pos = vec![0; cmp_count];
            for (i, &c) in cmp.iter().enumerate().rev() {
                pos[c] = i;
            }

            let mut ord_swp = vec![0; n];
            let mut insert = |i| {
                let c = cmp[ord_inverse[i]];
                ord_swp[pos[c]] = i;
                pos[c] += 1;
            };
            (n - d..n).for_each(&mut insert);
            ord.iter()
                .filter(|&&i| d <= i)
                .map(|i| i - d)
                .for_each(insert);

            let mut cmp_swp = vec![0; n];
            for i in 1..n {
                let l = ord_swp[i - 1];
                let r = ord_swp[i];
                cmp_swp[i] = if (
                    cmp[ord_inverse[l]],
                    ord_inverse.get(l + d).map(|&ld| cmp[ld]).unwrap_or(n),
                ) == (
                    cmp[ord_inverse[r]],
                    ord_inverse.get(r + d).map(|&rd| cmp[rd]).unwrap_or(n),
                ) {
                    cmp_swp[i - 1]
                } else {
                    cmp_swp[i - 1] + 1
                }
            }

            ord = ord_swp;
            cmp = cmp_swp;
        }
        ord
    }

    fn calc_lcp<T: Ord>(s: &[T], pos1: usize, pos2: usize, mut lcp: usize) -> usize {
        while pos1 + lcp < s.len() && pos1 + lcp < s.len() && s[pos1 + lcp] == s[pos2 + lcp] {
            lcp += 1;
        }
        lcp
    }

    pub fn lcp_array<T: Ord>(sa: &[usize], s: &[T]) -> Vec<usize> {
        let mut rank = vec![0; sa.len()];
        for (i, x) in sa.iter().copied().enumerate() {
            rank[x] = i;
        }

        let mut lcp_array = vec![0; sa.len()];
        let mut lcp = 0;
        for i in 0..sa.len() {
            let index = rank[i];
            let pos1 = sa[index];
            if index == sa.len() - 1 {
                lcp_array[index] = lcp;
                lcp = 0;
                continue;
            }

            let pos2 = sa[index + 1];
            lcp = calc_lcp(&s, pos1, pos2, lcp);
            lcp_array[index] = lcp;
            lcp = lcp.saturating_sub(1);
        }

        lcp_array
    }
}
// }}}

fn main() {
    input!(s: proconio::marker::Chars, l: u64, r: u64);
    let r = r + 1;
    let n = s.len();

    let sa = suffix_array::suffix_array(s.as_slice());
    let mut rank = vec![0; n];
    for (i, x) in sa.iter().copied().enumerate() {
        rank[x] = i;
    }

    let sparse_table =
        rmq::SparseTable::from_vec(suffix_array::lcp_array(sa.as_slice(), s.as_slice()));
    let lcp = |u: usize, v: usize| -> usize {
        if u == v {
            n - u
        } else {
            let l = rank[u];
            let r = rank[v];
            let (l, r) = (l.min(r), l.max(r));
            sparse_table.seq[sparse_table.query(l..r).unwrap()]
        }
    };

    let m = (1..n)
        .filter(|&i| i != n / 2 && lcp(0, i) == n - i)
        .last()
        .unwrap_or(n);

    let mut table = vec![[0; 26]; n + 1];
    for i in 0..n {
        let (left, right) = table.split_at_mut(i + 1);
        right[0].copy_from_slice(&left[i]);
        right[0][(s[i] as u8 - b'a') as usize] += 1;
    }
    fn add(a: &[u64; 26], b: &[u64; 26]) -> [u64; 26] {
        let mut c = [0; 26];
        for i in 0..26 {
            c[i] = a[i] + b[i];
        }
        c
    }

    fn sub(a: &[u64; 26], b: &[u64; 26]) -> [u64; 26] {
        let mut c = [0; 26];
        for i in 0..26 {
            c[i] = a[i] - b[i];
        }
        c
    }

    let mut seq = vec![(n as u64 / 2, table[n / 2]), (m as u64, table[m])];
    loop {
        let (m, count_m) = seq[seq.len() - 2];
        let (n, count_n) = seq[seq.len() - 1];
        seq.push((m + n, add(&count_m, &count_n)));
        if r < n + m {
            break;
        }
    }

    fn dfs(l: u64, r: u64, k: usize, seq: &[(u64, [u64; 26])], table: &[[u64; 26]]) -> [u64; 26] {
        let n = seq[k].0;
        assert!(l < r);
        assert!(r <= n);
        if k == 0 || k == 1 {
            sub(&table[r as usize], &table[l as usize])
        } else if l == 0 && r == n {
            seq[k].1
        } else {
            let c = seq[k - 1].0;
            let mut ans = [0; 26];
            if l < c {
                let swp = add(&ans, &dfs(l, r.min(c), k - 1, seq, table));
                ans = swp.clone();
            }
            if c < r {
                let swp = add(&ans, &dfs(0, r - l.max(c), k - 2, seq, table));
                ans = swp.clone();
            }
            ans
        }
    };

    println!(
        "{}",
        dfs(l, r, seq.len() - 1, &seq, &table)
            .iter()
            .map(|x| x.to_string())
            .fold(String::new(), |acc, x| if acc.is_empty() {
                x
            } else {
                acc + " " + x.as_ref()
            })
    );
}