分词
Time limit per test: 1.0 seconds
Time limit all tests: 1.0 seconds
Memory limit: 256 megabytes
有一句句子因为粘贴的时候出现了一点问题空格全部丢失了。现在给一本字典,每个词都对应这个词出现的频率(每十亿)。根据这个频率,我们可以根据下面的公式算出这个词带来的收益 P(word) :
其中 frequency 就是上面所提到的频率。 len 指的是单词的长度。
特别的,对于字典中没有出现过的词, P(word)=0 。
请对句子进行适当的分割,使得分割得到的所有词收益之和最大。同一个词可以重复出现,收益算作多次。
Input
先给出一本词典,词典的第一行是词条数(词条数约为 40 000 ),下面每行分别是单词和对应出现频率,用空格隔开。单词中只会出现英文字母大小写,不会有多余的空格。每个单词只会出现一次。频率是一个正实数。
所有单词长度之和不超过 3⋅105 ,最长单词长度不超过 30 。
接下来一行一个整数 T (T≤10) ,表示有 T 个查询。
下面 T 行,每行一个句子,句子长度不超过 5 000 。句子中保证只含有英文字母大小写。注意单词匹配时,不区分大小写。
词典数据来源于 Wikipedia Project Gutenberg(可能需要代理),其中 1-10000 词汇。
查询数据来源于 IELTS Test。
Output
对于每组数据,输出两行。
第一行是一个实数,表示最大能达到的收益。输出和答案相差不超过 10−3 即可认为正确。
第二行输出一连串单词,单词和单词之间用空格隔开。满足:
- 把这些单词依次串联起来可以得到原句子;
- 所有单词的收益值相加得到第一行的实数。
Examples
5 ano 10 ther 30 another 10 an 300 other 20 1 another
112.826670 another
5 ano 10.0 ther 30.0 another 10.0 an 300.0 other 2000.0 1 another
212.837691 an other
Note
样例给出的词典与测试数据有所不同。
Source
2017 华东师范大学网赛
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <cmath>
#include <map>
#include <bitset>
#include <set>
#include <vector>
#include <functional>
using namespace std;
#define LL long long
const int INF = 0x3f3f3f3f;
int n, t, f[300090][26], p[5005], visit[5005];
double g[300090], dp[5090], m;
char ch[5005], a[50];
int main()
{
while (~scanf("%d", &n))
{
memset(f[0], 0, sizeof f[0]);
int cnt = 0;
for (int i = 1; i <= n; i++)
{
scanf("%s%lf", a, &m);
int k = 0, len = strlen(a);
for (int j = len - 1; j >= 0; j--)
{
int x = a[j] >= 'a'&&a[j] <= 'z' ? a[j] - 'a' : a[j] - 'A';
if (!f[k][x])
{
f[k][x] = ++cnt;
memset(f[cnt], 0, sizeof f[cnt]);
g[cnt] = 0;
}
k = f[k][x];
}
g[k] = max(g[k], m);
}
scanf("%d", &t);
while (t--)
{
scanf("%s", ch + 1);
int len = strlen(ch + 1);
for (int i = 0; i <= len; i++) dp[i] = 0;
memset(p, -1, sizeof p);
for (int i = 1; i <= len; i++)
{
int k = 0, j;
for (j = i; j >= 1; j--)
{
int x = ch[j] >= 'a'&&ch[j] <= 'z' ? ch[j] - 'a' : ch[j] - 'A';
if (f[k][x])
{
k = f[k][x];
double xx = g[k] ? log(g[k]) : 0;
if (dp[i] < dp[j - 1] + (i - j + 1)*(i - j + 1)*xx)
dp[i] = dp[j - 1] + (i - j + 1)*(i - j + 1)*xx, p[i] = j - 1;
}
else break;
}
while (j >= 1)
{
if (dp[i] < dp[j - 1])
dp[i] = dp[j - 1], p[i] = j - 1;
j--;
}
}
printf("%.6lf\n", dp[len]);
memset(visit, 0, sizeof visit);
int k = len;
while (k != -1) { visit[k] = 1, k = p[k]; }
for (int i = 1; i <= len; i++)
{
if (visit[i] && i != len) printf("%c ", ch[i]);
else printf("%c", ch[i]);
}
printf("\n");
}
}
return 0;
}