题意:
题目链接:http://acm.ecnu.edu.cn/problem/3261/
给出一个词典,包括每个单词的频率,根据公式计算出单词的价值。现在给出一串字符串,要求将字符串分成若干单词,使得分割之后单词价值之后最大,并输出分割结果。
思路:
词典用字典树维护,对于每个字符串进行O(n^2)的dp,dp[j]=dp[i]+val[u],然后路径标记,输出结果即可。
代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 5005;
const int MAXNODE = 3e5 + 10;
const int SIGMA_SIZE = 30;
struct Trie {
int ch[MAXNODE][SIGMA_SIZE];
double val[MAXNODE];
int sz;
void init() {
sz = 1;
memset(ch, 0, sizeof(ch));
}
int idx(char c) {
return c - 'a';
}
void Insert(char *s, double v) {
int u = 0, n = strlen(s);
for (int i = 0; i < n; i++) {
int c = idx(s[i]);
if (!ch[u][c]) {
memset(ch[sz], 0, sizeof(ch[sz]));
val[sz] = 0;
ch[u][c] = sz++;
}
u = ch[u][c];
}
val[u] = v;
}
} trie;
char str[MAXN], ss[MAXN];
int pa[MAXN];
double dp[MAXN];
void show(int x) {
if (x == 0) return;
show(pa[x]);
if (pa[x] != 0) printf(" ");
for (int i = pa[x] + 1; i <= x; i++)
printf("%c", str[i]);
}
int main() {
//freopen("in.txt", "r", stdin);
int n, m;
scanf("%d", &n);
trie.init();
for (int i = 1; i <= n; i++) {
double x;
scanf("%s%lf", str, &x);
int len = strlen(str);
for (int j = 0; j < len; j++)
str[j] = tolower(str[j]);
double v = log(x) * len * len;
trie.Insert(str, v);
//cout << str << " " << v <<endl;
}
scanf("%d", &m);
while (m--) {
scanf("%s", str + 1);
int len = strlen(str +1);
for (int i = 1; i <= len; i++) {
ss[i] = tolower(str[i]);
}
memset(dp, 0, sizeof(dp));
memset(pa, 0, sizeof(pa));
for (int i = 0; i < len; i++) {
int u = 0, j = i + 1;
for (; j <= len; j++) {
int c = trie.idx(ss[j]);
u = trie.ch[u][c];
if (dp[j] < dp[i] + trie.val[u]) {
pa[j] = i;
dp[j] = dp[i] + trie.val[u];
}
if (u == 0) break;
}
}
printf("%.6f\n", dp[len]);
show(len);
puts("");
}
return 0;
}