玲珑杯 1007 Spoon Devil Love Game_i++

【题意】给了一个字符串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;
}