EOJ Problem #3261 分词 trie + dp + 小剪枝

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 ),下面每行分别是单词和对应出现频率,用空格隔开。单词中只会出现英文字母大小写,不会有多余的空格。每个单词只会出现一次。频率是一个正实数

所有单词长度之和不超过 3105 ,最长单词长度不超过 30

接下来一行一个整数 T (T10) ,表示有 T 个查询。

下面 T 行,每行一个句子,句子长度不超过 5 000 。句子中保证只含有英文字母大小写。注意单词匹配时,不区分大小写

词典数据来源于 Wikipedia Project Gutenberg(可能需要代理),其中 1-10000 词汇。

查询数据来源于 IELTS Test。

Output

对于每组数据,输出两行。

第一行是一个实数,表示最大能达到的收益。输出和答案相差不超过 103 即可认为正确。

第二行输出一连串单词,单词和单词之间用空格隔开。满足:

  • 把这些单词依次串联起来可以得到原句子;
  • 所有单词的收益值相加得到第一行的实数。

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\n", dp[lenstr].val);
        for (int i = 1; i <= lenstr; ++i) {
            if (del[i - 1] == DFN) {
                printf(" ");
            }
            printf("%c", sub[i]);
        }
        printf("\n");
    }
}

int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
#endif
    work();
    return 0;
}
View Code

 

 

转载于:https://www.cnblogs.com/liuweimingcprogram/p/6848751.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值