Obsessive String (Codeforces 495D)
Tags: DP, strings

Hamed has recently found a string t and suddenly became quite fond of it. He spent several days trying to find all occurrences of t in other strings he had. Finally he became tired and started thinking about the following problem. Given a string s how many ways are there to extract k ≥ 1 non-overlapping substrings from it such that each of them contains string t as a substring? More formally, you need to calculate the number of ways to choose two sequences a1, a2, ..., ak and b1, b2, ..., bk satisfying the following requirements:  k ≥ 1          t is a substring of string saisai + 1... sbi (string s is considered as 1-indexed). As the number of ways can be rather large print it modulo 109 + 7.

Input: Input consists of two lines containing strings s and t (1 ≤ |s|, |t| ≤ 105). Each string consists of lowercase Latin letters.

Output: Print the answer in a single line.


Sample Inputs:
ababa
aba

welcometoroundtwohundredandeightytwo
d

ddd
d

Sample Outputs:
5

274201

12

Solution (Python):
mod = 1000000007

def count_prefix(n, m, t):
    p = [0]
    k = 0
    for i in range(1, n + m + 1):
        while k and t[k] != t[i]:
            k = p[k - 1]
        if t[k] == t[i]:
            k += 1
        p.append(k)
    return p

def find_sum_ending(n, m, p):
    ans = [0] * n
    sums = [0] * (n + 1)
    curs = 0
    was = False
    j = 0
    for i in range(n):
        if p[i + m + 1] == m:
            if not was:
                was = True
                curs = 1
            while j <= i - m:
                curs = (curs + sums[j] + 1) % mod
                j += 1
        ans[i] = curs
        sums[i] = (sums[i - 1] + ans[i]) % mod
    return ans

def main():
    (s, t) = (input(), input())
    (n, m) = (len(s), len(t))
    t = '$'.join((t, s))
    p = count_prefix(n, m, t)
    ans = find_sum_ending(n, m, p)
    print(sum(ans) % mod)
main()

Solution (Python):
def main():
    (s, t) = (input(), input())
    (n, m) = (len(s), len(t))
    t = '$'.join((t, s))
    p = [0]
    k = 0
    for i in range(1, n + m + 1):
        while k and t[k] != t[i]:
            k = p[k - 1]
        if t[k] == t[i]:
            k += 1
        p.append(k)
    ans = [0] * n
    sums = [0] * (n + 1)
    curs = 0
    was = False
    j = 0
    MOD = 1000000007
    for i in range(n):
        if p[i + m + 1] == m:
            if not was:
                was = True
                curs = 1
            while j <= i - m:
                curs = (curs + sums[j] + 1) % MOD
                j += 1
        ans[i] = curs
        sums[i] = (sums[i - 1] + ans[i]) % MOD
    print(sum(ans) % MOD)
if __name__ == '__main__':
    main()

Solution (Python):
(s, t) = (input(), input())
(n, m) = (len(s), len(t))
t = '$'.join((t, s))
p = [0]
k = 0
for i in range(1, n + m + 1):
    while k and t[k] != t[i]:
        k = p[k - 1]
    if t[k] == t[i]:
        k += 1
    p.append(k)
ans = [0] * n
sums = [0] * (n + 1)
curs = 0
was = False
j = 0
mod = 1000000007
for i in range(n):
    if p[i + m + 1] == m:
        if not was:
            was = True
            curs = 1
        while j <= i - m:
            curs = (curs + sums[j] + 1) % mod
            j += 1
    ans[i] = curs
    sums[i] = (sums[i - 1] + ans[i]) % mod
print(sum(ans) % mod)