【NOIP2001】【LuoguP1026】统计单词个数
题目链接: https://www.luogu.org/problem/P1026
前言
这题要不是有DP标签我还真想不出这种思路。
分析
首先题目描述有点不清楚,结合样例更加好理解。差不多为,字符串长度不超过200,单词种类不超过6个,将字符串分40段求最大单词匹配总数。
然后给出了一个性质,一个字符自能被当做一次首字符,所以就可以用线性做法。
我们先预处理,求出每个单词在字符串中的所有匹配位置。那么如果几个单词重叠了该怎么办呢?
很容易想到,字符串中某字符被当做首字母时,匹配最短的单词最优。因此我们可以求出字符串中每一个字符当首字母时的最短长度。
如果使用string可以使用find函数,但输入时较为麻烦。所以我用char数组存储,并使用strstr函数。
接下来考虑DP方程。(因为有DP标签,才会拼凑DP思路,考场上还真不一定想出DP解法)
非常典型的设一个$F[N][K]$,表示处理到第N个字符,分割为K部分。
先上经典转移方程进行修改。
$$F[i][j] = max(F[i - 1][j], f[i - 1][j - 1])$$
但你会发现这样没地方加入预处理出的最短长度。因为后面转移时,单词有可能从中间被切开,这样求出答案就是错了。
然后就写了个鬼畜的方程,设$W_i$为字符串中第i字符当首字母时最短长度(如果不能匹配则无限大)。
所以$i$会影响到$i + W_i$后的答案,使他们答案+1,取个max。
然后我们以j为第一关键字,i为第二关键字枚举即可。因为我们分隔字符只会让答案变小,所以将方程改为。
$$F[i][j] = max(F[i][j], f[i - 1][j - 1])$$
代码
1 | #include <iostream> |