题目
小红定义一个字符串是可爱串,当且仅当该字符串包含子序列"red",且不包含子串"red"。我们定义子序列为字符串中可以不连续的一段,而子串则必须连续。例如rderd包含子序列"red",且不包含子串"red",因此该字符串为可爱串。小红想知道,长度为n的、仅由r、e、d三种字母组成的字符串中,有多少是可爱串? 答案请对10^9+7取模。数据范围:1≤n≤10^5
分析
设法求得所有包含子序列red(可连续)的方案数 A 和包含子串red的方案数 B,A - B 即为答案。
- 首先求 A:
-
假设 f(i) 表示长度为 i 的字符串中包含 red 子序列的方案数。f(i) = f(i-1) * 3 + g(i-1)
-
若该字符串以 r 或者 e 结尾,则 red 子序列在前 i - 1 个字母中,方案数为 f(i-1) * 2
-
若该字符串以 d 结尾,可分为以下两种情况
-
这个d不构成子序列 red 的一部分,即前 i - 1 个字母中存在 red 子序列,方案数为 f(i-1)
-
这个 d 必须构成子序列 red 的一部分,即前 i - 1 个字母中只有re子序列,没有 red
-
-
- 所以现在需要求长度为 i 的字符串中包含 re 子序列但不包含 red 的方案数,设其为 g(i)。
-
g(i) 表示长度为 i 的字符串中包含 re 子序列的方案数。g(i) = g(i-1) * 2 + 1
-
若该字符串以 d 结尾,而且前 i - 1个字母中存在 re 子序列,则必然构成 red 子序列,故此情况不存在 -
若该字符串以 r 结尾,则 re 子序列在前 i - 1 个字母中,方案数为 g(i-1)
-
若该字符串以 e 结尾,可分为以下两种情况
-
这个 e 不构成子序列 re 的一部分,即前 i - 1 个字母中存在 re 子序列,方案数为 g(i-1)
-
这个 e 必须构成子序列 re 的一部分,即前 i - 1 个字母中所有的 r 排在 e (if exist)的后面 ,r 有 i - 1个位置可以放,r的右边只能放置 r d,r的左边只能放置 e d 。所以方案数 = (i - 1) * 2^(i - 2)
-
-
- 求 B:
-
h(i) 表示长度为 i 的字符串中包含 red 子串的方案数。h(i) = 3 ^(i - 3) + h(i-1) * 3 - h(i-3)
-
若该字符串以 red 结尾,则前 i - 3 个字符可任意排列,方案数 = 3 ^(i - 3)
-
若该字符串不以 red 结尾,可分为以下两种情况
-
不以 d 结尾,则前 i - 1 个字母中存在 red 子串,方案数 = h(i-1) * 2
-
以 d 结尾,则前 i - 1 个字母中存在 red 子串 并且倒数两位不能是 re。所以方案数是 h(i-1) - h(i-3)
-
-
-
综上 A - B:f(n) - h(n)。
代码
#include <cstdio>
#include <vector>
#include <cmath>
int main() {
int n;
scanf("%d", &n);
std::vector<int> f(n + 1), g(n + 1), h(n + 1);
for (int i = 2; i <= n; i ++) g[i] = g[i-1] * 2 + (i - 1) * pow(2, i - 2);
for (int i = 3; i <= n; i ++) f[i] = f[i-1] * 3 + g[i-1];
for (int i = 3; i <= n; i ++) h[i] = pow(3, i - 3) + h[i-1] * 3 - h[i-3];
printf("%d %d %d", f[n], h[n], f[n] - h[n]);
}