又💧一篇
作者:hans774882968以及hans774882968
原问题要求去重,增加了分析的难度。若去掉该要求,则可以直接基于容斥原理来得到转移方程。仍然采用定义:dp[L][R]
为s[L~R]
中的回文子序列个数。仍然分s[L] == s[R]
和不相等来讨论。
- 不相等,则两端无法同时参与构建回文子序列,仍然根据容斥原理,得
dp[L][R] = dp[L + 1][R] + dp[L][R - 1] - dp[L + 1][R - 1]
。 - 相等,则在容斥原理式子的基础上加上两端同时参与的方案数。对于
t ∈ dp[L+1][R-1]
,加上两端的字符ch
,都合法。再加上ch + ch
,故为dp[L][R] = dp[L + 1][R] + dp[L][R - 1] + 1
。
class Solution:
def bf(self, s: str) -> int:
n = len(s)
ans = 0
for S in range(1, 1 << n):
t = ""
for i in range(n):
if S >> i & 1:
t += s[i]
if t == t[::-1]:
ans += 1
return ans
def countPalindromicSubsequences(self, s: str) -> int:
n, C, mod = len(s), 4, int(1e9) + 7
dp = [[0] * n for _ in range(n)]
for i in range(n):
dp[i][i] = 1
for L in range(n - 1, -1, -1):
for R in range(L + 1, n):
if s[L] == s[R]:
dp[L][R] = (dp[L + 1][R] + dp[L][R - 1] + 1) % mod
else:
dp[L][R] = ((dp[L + 1][R] + dp[L][R - 1] -
dp[L + 1][R - 1]) % mod + mod) % mod
if n <= 20:
assert dp[0][n - 1] == self.bf(s)
return dp[0][n - 1]
def test1(s):
for i in range(1, 8):
for it in itertools.product(*(['abcd'] * i)):
v = "".join(it)
s.countPalindromicSubsequences(v)