• 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
    ", 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;
    }
    View Code
     
  • 相关阅读:
    「从零单排canal 03」 canal源码分析大纲
    「从零单排canal 02」canal集群版 + admin控制台 最新搭建姿势(基于1.1.4版本)
    「从零单排canal 01」 canal 10分钟入门(基于1.1.4版本)
    实时数据订阅与分发系统概述
    使用phoenix踩的坑与设计思考
    「从零单排HBase 12」HBase二级索引Phoenix使用与最佳实践
    「从零单排HBase 11」HBase二级索引解决方案
    「从零单排HBase 10」HBase集群多租户实践
    「从零单排HBase 09」HBase的那些数据结构和算法
    Netty源码分析之自定义编解码器
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/6848751.html
Copyright © 2020-2023  润新知