【题意】给了一个字符串x,然后给了一些字串,每一个字串有一个价值,字串可重复,现在要你选一些字串来拼成这个字符串,问你能得到最大价值是什么?

【解题方法】很明显我们能想到这样一个状态:dp[i]代表以第i个字母结尾能取得的最大值是多少。那么如果第j个字符串与以i结尾的原串匹配成功了,那么dp[i]=max(dp[i],dp[i-len(第j个字符串长度)]+w[i])(我字符串下标从0开始DP枚举从1开始)。考虑到有-1存在,那么我们初始化所有为-1,dp[0]=0;然后如果dp[i-len]==-1显然状态是不可到达的,所以要舍去。这个题如果完全暴力复杂度是NLEN(X)30,可以险过。还可以采取用字典树的方式,逆向插入。然后枚举以i结尾去查找字典树(最多30层),复杂度为N*30。

【PS】我这里用的第一种方法,800ms过去了。

【AC 代码】

//
//Created by just_sort 2016/9/26 21:26
//Copyright (c) 2016 just_sort.All Rights Reserved
//

#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int dp[10010];
int w[1010],len[1010];
char s[1010][32],x[10010];
int n,k;
int main()
{
    while(scanf("%d%s",&n,x)!=EOF)
    {
        for(int i = 1; i <= n; i++) scanf("%s%d",s[i],&w[i]);
        for(int i = 1; i <= n; i++) len[i] = strlen(s[i]);
        memset(dp,-1,sizeof(dp));
        dp[0] = 0;
        int le = strlen(x);
        for(int i = 1; i <= le; i++){
            for(int j = 1; j <= n; j++){
                if(len[j] > i) continue;
                for(k = 0; k < len[j]; k++){
                    if(x[i-k-1] != s[j][len[j]-k-1])
                        break;
                }
                if(k < len[j]) continue;
                if(dp[i-len[j]] == -1) continue;
                dp[i] = max(dp[i],dp[i-len[j]] + w[j]);
            }
        }
        printf("%d\n", dp[le]);
    }
    return 0;
}