Blackops

初心易得,始终难守

0%

HDU 2296 Ring(AC自动机+DP)

Ring

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3970 Accepted Submission(s): 1318

Problem Description
For the hope of a forever love, Steven is planning to send a ring to Jane with a romantic string engraved on. The string’s length should not exceed N. The careful Steven knows Jane so deeply that he knows her favorite words, such as “love”, “forever”. Also, he knows the value of each word. The higher value a word has the more joy Jane will get when see it.
The weight of a word is defined as its appeared times in the romantic string multiply by its value, while the weight of the romantic string is defined as the sum of all words’ weight. You should output the string making its weight maximal.

Input
The input consists of several test cases. The first line of input consists of an integer T, indicating the number of test cases. Each test case starts with a line consisting of two integers: N, M, indicating the string’s length and the number of Jane’s favorite words. Each of the following M lines consists of a favorite word Si. The last line of each test case consists of M integers, while the i-th number indicates the value of Si.
Technical Specification

  1. T ≤ 15
  2. 0 < N ≤ 50, 0 < M ≤ 100.
  3. The length of each word is less than 11 and bigger than 0.
  4. 1 ≤ Hi ≤ 100.
  5. All the words in the input are different.
  6. All the words just consist of ‘a’ - ‘z’.

Output
For each test case, output the string to engrave on a single line.
If there’s more than one possible answer, first output the shortest one. If there are still multiple solutions, output the smallest in lexicographically order.

The answer may be an empty string.

Sample Input
2
7 2
love
ever
5 5
5 1
ab
5

Sample Output
lovever
abab

Hint

Sample 1: weight(love) = 5, weight(ever) = 5, so weight(lovever) = 5 + 5 = 10
Sample 2: weight(ab) = 2 * 5 = 10, so weight(abab) = 10

题目链接:HDU 2296
题意就是让你构造长度不大于$n$的字符串,使得其总价值最大,其中总价值的定义为所有题中所给$子串的价值*子串在构造串中出现次数$,那么显然用$dp[i][j]$表示当前构造长度为$i$,走到了第$j$个节点的最大总价值,由于题目还要求了长度尽量短、字典序尽量小,因此用$dps[i][j]$记录$dp[i][j]$的最优方案,这里有一个问题,如果fail指针指向的位置也是结束位置也要将它的价值传递到当前串的价值里即:$L[u].value+=L[L[u].fail].value$,因为一旦存在$fail$指向结束位置,说明指向的串是当前串的后缀的前缀(子串的定义不就是后缀的前缀或者前缀的后缀吗),因此要把价值累加上去。
转移方程很显然,然后一开始要将$dp$初始化为$-\infty$,考虑到合法性的问题,因为不是所有的位置都可以进行转移,不然所有长度大于$1$的字符串都会在枚举的长度小于当前长度的时候就被考虑了,实际上这是不可能存在的,最后要特判一下空串:当最大总价值为$0$的时候,空串显然是长度和字典序都最优的解
转移方程:

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <bitset>
#include <string>
#include <stack>
#include <cmath>
#include <queue>
#include <set>
#include <map>
using namespace std;
#define INF 0x3f3f3f3f
#define LC(x) (x<<1)
#define RC(x) ((x<<1)+1)
#define MID(x,y) ((x+y)>>1)
#define fin(name) freopen(name,"r",stdin)
#define fout(name) freopen(name,"w",stdout)
#define CLR(arr,val) memset(arr,val,sizeof(arr))
#define FAST_IO ios::sync_with_stdio(false);cin.tie(0);
typedef pair<int, int> pii;
typedef long long LL;
const double PI = acos(-1.0);
const int N = 1000;
struct Trie
{
int nxt[26];
int v, fail;
void init()
{
for (int i = 0; i < 26; ++i)
nxt[i] = -1;
fail = v = 0;
}
} L[N];
int sz;
int dp[55][N], val[55];
char S[105][105];
char dps[55][N][55];

namespace ac
{
void init()
{
sz = 0;
L[sz++].init();
}
void ins(char s[], int len, int v)
{
int u = 0;
for (int i = 0; i < len; ++i)
{
int v = s[i] - 'a';
if (L[u].nxt[v] == -1)
{
L[sz].init();
L[u].nxt[v] = sz++;
}
u = L[u].nxt[v];
}
L[u].v += v;
}
void build()
{
L[0].fail = 0;
queue<int>Q;
for (int i = 0; i < 26; ++i)
{
int v = L[0].nxt[i];
if (~v)
{
L[v].fail = 0;
Q.push(v);
}
else
L[0].nxt[i] = 0;
}
while (!Q.empty())
{
int u = Q.front();
Q.pop();
int uf = L[u].fail;
if (L[uf].v)
L[u].v += L[uf].v;
for (int i = 0; i < 26; ++i)
{
int v = L[u].nxt[i];
if (~v)
{
L[v].fail = L[uf].nxt[i];
Q.push(v);
}
else
L[u].nxt[i] = L[uf].nxt[i];
}
}
}
}
inline bool _lt(char a[], char b[])
{
int la = strlen(a), lb = strlen(b);
if (la < lb)
return true;
else if (la > lb)
return false;
else
{
for (int i = 0; i < la; ++i)
{
if (a[i] < b[i])
return true;
else if (a[i] > b[i])
return false;
}
return false;
}
}
int main(void)
{
int T, n, m, i, j;
scanf("%d", &T);
while (T--)
{
ac::init();
CLR(dps, 0);
scanf("%d%d", &n, &m);
for (i = 0; i < m; ++i)
scanf("%s", S[i]);
for (i = 0; i < m; ++i)
scanf("%d", &val[i]);
for (i = 0; i < m; ++i)
ac::ins(S[i], strlen(S[i]), val[i]);
ac::build();
CLR(dp, -INF);
dp[0][0] = 0;
int ans = -1;
char temp[55], ans_str[N];
for (i = 0; i < n; ++i)
{
for (j = 0; j < sz; ++j)
{
if (dp[i][j] < 0)
continue;
for (int k = 0; k < 26; ++k)
{
int v = L[j].nxt[k];
int R = dp[i][j] + L[v].v;
strcpy(temp, dps[i][j]);
int len = strlen(dps[i][j]);
temp[len] = 'a' + k;
temp[len + 1] = '\0';
if (dp[i + 1][v] < R || (R == dp[i + 1][v] && _lt(temp, dps[i + 1][v])))
{
dp[i + 1][v] = R;
strcpy(dps[i + 1][v], temp);
if (ans < dp[i + 1][v] || (ans == dp[i + 1][v] && _lt(temp, ans_str)))
{
ans = dp[i + 1][v];
strcpy(ans_str, temp);
}
}
}
}
}
printf("%s\n", ans ? ans_str : "");
}
return 0;
}