题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2296
解题思路:
给出n个串和串的价值,询问长度为L的串最多能拥有的价值,并输出价值最大的串中长度最小中字典序最小的串。
AC自动机的作用是跑到最长相同后缀对应的单词前缀处使得最快到达下一个单词
DP:
定义:
dp[i][j]表示长度为i,且第i个字母对应AC自动机节点j的字符串的最大价值
string rec[i][j],记录对应dp位置的这个字符串
初始状态:
dp[0][0] = 0, rec[0][0] = "";
状态转移:
枚举当前状态的所有子节点去更新:v表示子节点,u表示当前节点,val[v]表示v节点后缀链接上所有单词价值和.(到达这个节点,所有后缀的单词相当于都到过了)
即 dp[i+1][v] = max(dp[i+1][v],dp[i][u]+val[v]),然后储存的字符串相当暴力的一起对应修改就可以了
问题1:为什么rec[][]不能开一维,要开二维:
只开一维储存当前枚举长度到各个节点的最大价值,乍一看没有问题,但是在当前层DP调用某rec[u]时,他可能是当前层更新好的字符串,实际上极有可能已经“面目全非”而且长度也不对,这个错误随着DP的进行逐渐放大,最后求出来的就是长度过长且不对的答案
同时,我们开二维还解决了一个问题:价值相同时,我们要优先取最短的,因此rec[][]储存不同长度下价值最大后保证字典序最小的串。
问题2:当前的状态究竟能否去更新子节点:
只有被更新过(当前长度能到)的节点才能去更新子节点,因此我们把dp初始化为0?不,0不行,没走到一个单词末尾都是0,因此dp=0的点是要更新的,所以我们初始化为-1,这样如果它能被更新了,至少会变为0.
这样枚举当前长度i时,对于dp[i][] = -1的,直接跳过
代码:
#include
#include
#include
#include
#include
#include