http://acm.ecnu.edu.cn/problem/3261/
分词
Time limit per test: 1.0 seconds
Time limit all tests: 1.0 seconds
Memory limit: 256 megabytes
有一句句子因为粘贴的时候出现了一点问题空格全部丢失了。现在给一本字典,每个词都对应这个词出现的频率(每十亿)。根据这个频率,我们可以根据下面的公式算出这个词带来的收益 P(word) :
P(word)=len2(word)⋅ln(frequency(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
Input
5 ano 10 ther 30 another 10 an 300 other 20 1 another
Output
112.826670 another
Input
5 ano 10.0 ther 30.0 another 10.0 an 300.0 other 2000.0 1 another
Output
212.837691 an other
Note
样例给出的词典与测试数据有所不同。
Source
2017 华东师范大学网赛可以把所有字典都放进去字典树中,因为匹配的时候无视大小写,所以我们可以压小写进去就行了。
当然:
1、这样的话ABC和abc一样,取个价值大的就好。
2、价值公式:len * len * log(val),这个log,会变成负数,这样还不如不要,所以要娶个max(0, val)
TLE hack:
注意题目,我一直TLE, 队友带飞。
长度大于30的直接是0了
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <assert.h> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; #include <iostream> #include <sstream> #include <vector> #include <set> #include <map> #include <queue> #include <string> #include <bitset> const int maxn = 4e5 + 20; const int N = 26; char str[maxn]; struct Node { double val; struct Node * pNext[N]; } tree[maxn]; int t; struct Node * create() { struct Node *p = &tree[t++]; p->val = 0; return p; } void toInsert(struct Node **T, char str[], double val, int lenstr) { struct Node *p = *T; if (!p) p = *T = create(); for (int i = 1; str[i]; ++i) { int id = str[i] - 'a'; if (!p->pNext[id]) p->pNext[id] = create(); p = p->pNext[id]; } p->val = max(p->val, val); } double ask(struct Node *T, char str[], int be, int en) { if (en - be + 1 > 30) return 0; struct Node *p = T; if (!p) return 0; for (int i = be; i <= en; ++i) { int id = str[i] - 'a'; if (!p->pNext[id]) return 0; p = p->pNext[id]; } return p->val; } struct ddpp { double val; int pre; } dp[maxn]; int del[maxn], DFN; bool isok(char ch) { return ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z'; } void toChange(char str[], int lenstr) { for (int i = 1; i <= lenstr; ++i) { if (str[i] >= 'A' && str[i] <= 'Z') { str[i] += 32; } } } char sub[maxn]; void work() { int n; scanf("%d", &n); struct Node *T = NULL; for (int i = 1; i <= n; ++i) { scanf("%s", str + 1); double val; scanf("%lf", &val); int lenstr = strlen(str + 1); toChange(str, lenstr); toInsert(&T, str, lenstr * lenstr * log(val), lenstr); } int q; scanf("%d", &q); while (q--) { scanf("%s", str + 1); int lenstr = strlen(str + 1); strcpy(sub + 1, str + 1); toChange(str, lenstr); for (int i = 1; i <= lenstr; ++i) { dp[i].val = dp[i].pre = 0; for (int j = 1; j <= i; ++j) { double res = ask(T, str, j, i); if (dp[i].val < dp[j - 1].val + res) { dp[i].val = dp[j - 1].val + res; dp[i].pre = j - 1; } } } ++DFN; int pre = dp[lenstr].pre; while (pre > 0) { del[pre] = DFN; pre = dp[pre].pre; } printf("%0.10f ", dp[lenstr].val); for (int i = 1; i <= lenstr; ++i) { if (del[i - 1] == DFN) { printf(" "); } printf("%c", sub[i]); } printf(" "); } } int main() { #ifdef local freopen("data.txt", "r", stdin); #endif work(); return 0; }