思路:先把字符串转化为对应数字,然后把这些插入SET(其实建个字典树会更好一些),然后每次dp[i] = max(dp[i], dp[j] + 1) {存在i到j的字符串)
代码:
#include <cstdio>
#include <cstring>
#include <map>
#include <string>
using namespace std;
typedef unsigned long long ull;
const int N = 105;
const ull x = 123;
const int INF = 0x3f3f3f3f;
char str[50005][55], to[255];
char s[N];
int n;
ull hash[N], mi[N];
//map<ull, int> id;
map<string, int> id;
int dp[N], path[N][2];
void print(int u) {
if (path[u][0] == 0) {
printf("%s", str[path[u][1]]);
return;
}
print(path[u][0]);
printf(" %s", str[path[u][1]]);
}
char ss[50005][55];
int main() {
to['i'] = to['j'] = '1';
to['a'] = to['b'] = to['c'] = '2';
to['d'] = to['e'] = to['f'] = '3';
to['g'] = to['h'] = '4';
to['k'] = to['l'] = '5';
to['m'] = to['n'] = '6';
to['p'] = to['r'] = to['s'] = '7';
to['t'] = to['u'] = to['v'] = '8';
to['w'] = to['x'] = to['y'] = '9';
to['o'] = to['q'] = to['z'] = '0';
mi[0] = 1;
for (int i = 1; i < N; i++) mi[i] = mi[i - 1] * x;
while (~scanf("%s", s + 1)) {
int m = strlen(s + 1);
for (int i = 1; i <= m; i++)
hash[i] = hash[i - 1] * x + s[i];
scanf("%d", &n);
id.clear();
for (int i = 1; i <= n; i++) {
scanf("%s", str[i]);
int len = strlen(str[i]);
ull s = 0;
for (int j = 0; j < len; j++) {
s = s * x + to[str[i][j]];
ss[i][j] = to[str[i][j]];
}
ss[i][len] = '\0';
//id[s] = i;
id[ss[i]] = i;
}
memset(dp, INF, sizeof(dp));
dp[0] = 0;
char sb[105];
for (int i = 1; i <= m; i++) {
for (int j = 0; j < i; j++) {
strcpy(sb, s + j + 1);
sb[i - j] = '\0';
ull tmp = hash[i] - hash[j] * mi[i - j];
if (id.count(sb)) {
if (dp[i] > dp[j] + 1) {
dp[i] = dp[j] + 1;
path[i][0] = j;
path[i][1] = id[sb];
}
}
}
}
if (dp[m] == INF) printf("No solution.\n");
else {
print(m);
printf("\n");
}
}
return 0;
}