Problem:
Score : 500 points

Problem Statement

Takahashi has a string S of length N consisting of digits from 0 through 9.

He loves the prime number P. He wants to know how many non-empty (contiguous) substrings of S - there are N \times (N + 1) / 2 of them - are divisible by P when regarded as integers written in base ten.

Here substrings starting with a 0 also count, and substrings originated from different positions in S are distinguished, even if they are equal as strings or integers.

Compute this count to help Takahashi.

Constraints

1 \leq N \leq 2 \times 10^5

S consists of digits.

|S| = N

2 \leq P \leq 10000

P is a prime number.

Input

Input is given from Standard Input in the following format:

N P
S

Output

Print the number of non-empty (contiguous) substrings of S that are divisible by P when regarded as an integer written in base ten.

Sample Input 1

4 3
3543

Sample Output 1

6

Here S = 3543. There are ten non-empty (contiguous) substrings of S:

3: divisible by 3.

35: not divisible by 3.

354: divisible by 3.

3543: divisible by 3.

5: not divisible by 3.

54: divisible by 3.

543: divisible by 3.

4: not divisible by 3.

43: not divisible by 3.

3: divisible by 3.

Six of these are divisible by 3, so print 6.

Sample Input 2

4 2
2020

Sample Output 2

10

Here S = 2020. There are ten non-empty (contiguous) substrings of S, all of which are divisible by 2, so print 10.

Note that substrings beginning with a 0 also count.

Sample Input 3

20 11
33883322005544116655

Sample Output 3

68

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

// This code is generated by [cargo-atcoder](https://github.com/tanakh/cargo-atcoder)
// Original source code:
/*
use proconio::input;

// 2でも5でもない場合
// * 10はpで割り切れるかに関係ない。
//
// 2か5
// 末尾を見れば簡単
//
//
// 上からi桁目が右端となる数
//
// 更新は上を使う場合と使わない場合

fn main() {
    input! {
        n: usize,
        p: usize,
        s: String,
    }

    let s_rev: Vec<usize> = s.chars().rev().map(|c| c.to_digit(10).unwrap() as usize).collect();

    if p == 2 || p == 5 {
        let mut ans = 0;
        for (i, d) in s_rev.into_iter().enumerate() {
            if d % p == 0 {
                ans += n - i;
            }
        }

        println!("{}", ans);
        return;
    }

    let mut modp = vec![0; n];
    let mut base = 1;
    for (i, d) in s_rev.iter().enumerate() {
        if i >= 1 {
            modp[i] = ((d * base) % p + modp[i - 1]) % p;
        } else {
            modp[i] = d % p;
        }
        base = (base * 10) % p;
    }

    let mut counts = vec![0; p];
    counts[0] = 1;
    for &a in &modp {
        counts[a] += 1;
    }

    // eprintln!("{:?}", counts);

    let mut ans = 0;
    for m in counts.into_iter() {
        if m >= 1 {
            ans += m * (m - 1) / 2;
        }
    }

    println!("{}", ans);
}

// fn binom_coef(n: usize, k: usize) -> usize {
//     if n < k {
//         return 0;
//     }
//
//     if n - k < k {
//         return binom_coef(n, n - k);
//     }
//
//     let mut ret = 1;
//     for i in 1..(k + 1) {
//         ret = ret * (n - k + i) / i
//     }
//     ret
// }
//
// mod modint {
//     use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
//
//     pub const MODULO: usize = 1_000_000_007;
//     // pub const MODULO: usize = 11;
//
//     fn positive_rem(a: isize, b: usize) -> usize {
//         let b = b as isize;
//         let mut value = a % b;
//         if value < 0 {
//             value += b;
//         }
//         // TODO: TryFrom
//         value as usize
//     }
//
//     /// Return (x, y) s.t. ax + by = d where d = gcd(a, b)
//     #[allow(unused)]
//     pub fn ext_gcd(a: usize, b: usize) -> (isize, isize) {
//         if b == 0 {
//             return (1, 0);
//         }
//
//         let q = (a / b) as isize;
//         let r = a % b;
//         let (x1, y1) = ext_gcd(b, r);
//         (y1, x1 - q * y1)
//     }
//
//     #[derive(Debug, Copy, Clone)]
//     pub struct ModInt(pub usize);
//
//     impl From<usize> for ModInt {
//         fn from(n: usize) -> ModInt {
//             ModInt(n % MODULO)
//         }
//     }
//
//     impl From<isize> for ModInt {
//         fn from(n: isize) -> ModInt {
//             // TODO: use TryFrom
//             ModInt(positive_rem(n, MODULO as usize))
//         }
//     }
//
//     impl From<i32> for ModInt {
//         fn from(n: i32) -> ModInt {
//             // TODO: use TryFrom
//             ModInt(positive_rem(n as isize, MODULO as usize))
//         }
//     }
//
//     impl ModInt {
//         #[allow(unused)]
//         pub fn pow(self, p: usize) -> ModInt {
//             if self == ModInt::from(0) {
//                 return ModInt::from(0);
//             }
//             if p == 0 {
//                 return ModInt::from(1);
//             }
//
//             if p % 2 == 0 {
//                 let half = self.pow(p / 2);
//                 half * half
//             } else {
//                 self.pow(p - 1) * self
//             }
//         }
//
//         // when MODULO is prime
//         #[allow(unused)]
//         pub fn inv(self) -> ModInt {
//             let (x, _) = ext_gcd(self.0 as usize, MODULO as usize);
//             ModInt::from(x)
//         }
//     }
//
//     impl Add for ModInt {
//         type Output = ModInt;
//
//         fn add(self, other: ModInt) -> ModInt {
//             ModInt::from(self.0 + other.0)
//         }
//     }
//
//     impl Sub for ModInt {
//         type Output = ModInt;
//
//         fn sub(self, other: ModInt) -> ModInt {
//             ModInt::from(self.0 as isize - other.0 as isize)
//         }
//     }
//
//     impl Mul for ModInt {
//         type Output = ModInt;
//
//         fn mul(self, other: ModInt) -> ModInt {
//             ModInt::from(self.0 * other.0)
//         }
//     }
//
//     impl Neg for ModInt {
//         type Output = ModInt;
//
//         fn neg(self) -> Self::Output {
//             ModInt::from(0) - self
//         }
//     }
//
//     impl AddAssign for ModInt {
//         fn add_assign(&mut self, other: Self) {
//             *self = *self + other;
//         }
//     }
//
//     impl MulAssign for ModInt {
//         fn mul_assign(&mut self, other: Self) {
//             *self = *self * other;
//         }
//     }
//
//     impl SubAssign for ModInt {
//         fn sub_assign(&mut self, other: Self) {
//             *self = *self - other;
//         }
//     }
//
//     impl PartialEq for ModInt {
//         fn eq(&self, &other: &Self) -> bool {
//             self.0 == other.0
//         }
//     }
//
//     impl Eq for ModInt {}
//
//     #[derive(Debug)]
//     pub struct ModIntUtil {
//         factorial: Vec<ModInt>,
//         factorial_inv: Vec<ModInt>,
//         inv: Vec<ModInt>,
//     }
//
//     impl ModIntUtil {
//         #[allow(unused)]
//         pub fn new() -> ModIntUtil {
//             ModIntUtil {
//                 factorial: vec![ModInt::from(1), ModInt::from(1)],
//                 factorial_inv: vec![ModInt::from(1), ModInt::from(1)],
//                 inv: vec![ModInt::from(0), ModInt::from(1)],
//             }
//         }
//
//         fn calc_cache(&mut self, n: usize) {
//             let len = self.factorial.len();
//             if len < n + 1 {
//                 for i in len..(n + 1) {
//                     let prev = *self.factorial.last().unwrap();
//                     self.factorial.push(prev * ModInt::from(i));
//
//                     let inv_i = -self.inv[MODULO % i] * ModInt::from(MODULO / i);
//                     self.inv.push(inv_i);
//
//                     let prev = *self.factorial_inv.last().unwrap();
//                     self.factorial_inv.push(prev * self.inv[i]);
//                 }
//             }
//         }
//
//         #[allow(unused)]
//         pub fn factorial(&mut self, n: usize) -> ModInt {
//             self.calc_cache(n);
//             self.factorial[n]
//         }
//
//         #[allow(unused)]
//         pub fn factorial_inv(&mut self, n: usize) -> ModInt {
//             self.calc_cache(n);
//             self.factorial_inv[n]
//         }
//
//         // when MODULO is prime
//         #[allow(unused)]
//         pub fn binom_coef(&mut self, n: usize, k: usize) -> ModInt {
//             if n < k {
//                 return ModInt::from(0);
//             }
//
//             self.calc_cache(n);
//             self.factorial[n] * self.factorial_inv[k] * self.factorial_inv[n - k]
//         }
//
//         #[allow(unused)]
//         fn perm(&mut self, n: usize, k: usize) -> ModInt {
//             if n < k {
//                 return ModInt::from(0);
//             }
//             self.factorial(n) * self.factorial_inv(n - k)
//         }
//
//         // Not tested!!
//         #[allow(unused)]
//         pub fn multi_coef(&mut self, v: &[usize]) -> ModInt {
//             let n = v.iter().sum();
//             self.calc_cache(n);
//
//             let mut ret = ModInt::from(1);
//             ret *= self.factorial[n];
//             for v_i in v {
//                 ret *= self.factorial_inv[*v_i];
//             }
//
//             ret
//         }
//     }
// }
*/

fn main() {
    let exe = "/tmp/bin8ADB3B68";
    std::io::Write::write_all(&mut std::fs::File::create(exe).unwrap(), &decode(BIN)).unwrap();
    std::fs::set_permissions(exe, std::os::unix::fs::PermissionsExt::from_mode(0o755)).unwrap();
    std::process::exit(std::process::Command::new(exe).status().unwrap().code().unwrap())
}

fn decode(v: &str) -> Vec<u8> {
    let mut ret = vec![];
    let mut buf = 0;
    let mut tbl = vec![64; 256];
    for i in 0..64 { tbl[TBL[i] as usize] = i as u8; }
    for (i, c) in v.bytes().filter_map(|c| { let c = tbl[c as usize]; if c < 64 { Some(c) } else { None } }).enumerate() {
        match i % 4 {
            0 => buf = c << 2,
            1 => { ret.push(buf | c >> 4); buf = c << 4; }
            2 => { ret.push(buf | c >> 2); buf = c << 6; }
            3 => ret.push(buf | c),
            _ => unreachable!(),
        }
    }
    ret
}

const TBL: &'static [u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
const BIN: &'static str = "<base64-encoded ELF executable removed>";