📅  最后修改于: 2023-12-03 15:42:20.677000             🧑  作者: Mango
本题属于门|门 CS 1996级 《计算机程序设计竞赛》题目第39题,是一道算法题目。题目要求参赛者设计一种算法,对于一组输入数据能够求出相应的输出结果。
给定一个长度为 $N$ 的字符串 $s$ 和 $m$ 个长度为 $N$ 的字符串 $t_i$,需要将 $s$ 分成 $m+1$ 段,每段都是 $t_i$ 的子串。请问有多少种划分方案。
3
aba
1
aba
2
这里给出一种基于状压 DP 的思路,大体思路如下:
对于前 $i$ 个字符,先尝试把 $s[1 \cdots i]$ 分成 $j$ 份,然后再用状压表示这 $j$ 份中每一份是否等于 $t_k$ 中的某个子串(不超过 $10$ 个)。在最后一位的时候计算答案。
状态可以表示为 $f[i][S][j]$,表示前 $i$ 个字符且第 $j$ 份中每一份都是 $S$ 这个状态下的 $t_k$ 中的子串,相应的转移可以使用位运算和字符串匹配来实现。
时间复杂度 $O(N3^N)$,可以通过本题。
更详细的解题思路可以参考我的博客:https://www.cnblogs.com/champagne/p/14555356.html
def solve():
N = int(input())
s = input().strip()
m = int(input())
t = [input().strip() for i in range(m)]
mod = 10**9+7
dp = [[[[0]*(m+1) for j in range(1<<m)] for k in range(N+1)] for i in range(N+1)]
for j in range(1<<m):
for k in range(m):
dp[0][j][0][k] = 1
for i in range(1, N+1):
for j in range(1<<m):
for k in range(1, m+1):
for l in range(m):
if not((1<<l)&j) or t[l] not in s[i-len(t[l]):i]:
continue
cur = dp[i-len(t[l])][j^(1<<l)][k-1][l]
dp[i][j][k][l] = (dp[i][j][k][l] + cur)%mod
for k in range(1, m+1):
for j in range(1<<m):
cur = sum(dp[i][j][k-1])
dp[i][j][k][m] = (dp[i][j][k][m] + cur)%mod
ans = sum(dp[N][(1<<m)-1][m])
print(ans%mod)
solve()
代码片段需按markdown标明