Java easy to understand(Dynamic Programming + KMP)
\nclass Solution {\n    Integer[][][][] dp;\n    int mod = 1000000007;\n    int[] lps;\n    private int add(int a, int b) {\n        return (a % mod + b % mod) 
```\nclass Solution {\n    Integer[][][][] dp;\n    int mod = 1000000007;\n    int[] lps;\n    private int add(int a, int b) {\n        return (a % mod + b % mod) % mod;\n    }\n    private int solve(char[] s1, char[] s2, int cur, boolean isStrictLower, boolean isStrictUpper, char[] evil, int evI) {\n        if(evI == evil.length) return 0;\n        if(cur == s2.length) return 1;\n        if(dp[cur][isStrictLower ? 1 : 0][isStrictUpper ? 1 : 0][evI] != null) return dp[cur][isStrictLower ? 1 : 0][isStrictUpper ? 1 : 0][evI];\n        char start = isStrictLower ? s1[cur] : \'a\';\n        char end = isStrictUpper ? s2[cur] : \'z\';\n        int res = 0;\n        for(char ch = start; ch <= end; ch ++) {\n            if(evil[evI] == ch)\n                res = add(res, solve(s1, s2, cur + 1, isStrictLower && ch == start, isStrictUpper && ch == end, evil, evI + 1));\n            else {\n                int j = evI;\n                while (j > 0 && evil[j] != ch) j = lps[j - 1];\n                if (ch == evil[j]) j++;\n                res = add(res, solve(s1, s2, cur + 1, isStrictLower && ch == start, isStrictUpper && ch == end, evil, j));\n            }\n        }\n        return dp[cur][isStrictLower ? 1 : 0][isStrictUpper ? 1 : 0][evI] = res;\n    }\n    public int findGoodStrings(int n, String s1, String s2, String evil) {\n        char[] arr = s1.toCharArray();\n        char[] brr = s2.toCharArray();\n        char[] crr = evil.toCharArray();\n        lps = new int[crr.length];\n        for (int i = 1, j = 0; i < crr.length; i++) {\n            while (j > 0 && crr[i] != crr[j]) j = lps[j - 1];\n            if (crr[i] == crr[j]) lps[i] = ++j;\n        }\n        dp = new Integer[n][2][2][crr.length];\n        return solve(arr, brr, 0, true, true, crr, 0);\n    }\n}\n```
['Java']