zoukankan      html  css  js  c++  java
  • 大学生程序设计邀请赛(华东师范大学)B. 分词 DP

    B. 分词

     

    有一句句子因为粘贴的时候出现了一点问题空格全部丢失了。现在给一本字典,每个词都对应这个词出现的频率(每十亿)。根据这个频率,我们可以根据下面的公式算出这个词带来的收益 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

    样例给出的词典与测试数据有所不同。

    题解:

      将字典建立AC自动机

      设定dp[i]表示前i个字母划分可以得到的最大价值

      那么它可以转移的地方就是 i - 当前的失配指针指向的trie树上的节点所表示的母串长度

      直接暴力转移就行了。

      同时用pre记录当前最优是从哪个决策点转过来的

    #include<bits/stdc++.h>
    using namespace std;
    #pragma comment(linker, "/STACK:102400000,102400000")
    #define ls i<<1
    #define rs ls | 1
    #define mid ((ll+rr)>>1)
    #define pii pair<int,int>
    #define MP make_pair
    typedef long long LL;
    const long long INF = 1e18+1LL;
    const double Pi = acos(-1.0);
    const int N = 5e5+10, M = 1e3+20, mod = 1e9+7,inf = 2e5;
    
    double sum[N];
    int len[N],nex[N][27],cnt,head,tail,fail[N],q[N];
    
    int ID(char ch) {
        if(ch >= 'A' && ch <= 'Z') return ch - 'A';
        else return ch - 'a';
    }
    void insert(char *s,double x) {
        int now = 1, le = strlen(s);
        for(int i = 0; i < le; ++i) {
            int index = ID(s[i]);
            if(!nex[now][index])
                nex[now][index] = ++cnt;
            len[nex[now][index]] = len[now]+1;
            now = nex[now][index];
        }
        sum[now] = max(sum[now],x);
    }
    void build_fail() {
        head = 0, tail = 0;
        for(int i = 0; i < 26; ++i) nex[0][i] = 1;
        fail[1] = 0;
        q[tail++] = 1;
        while(head != tail) {
            int now = q[head++];
            for(int i = 0; i < 26; ++i) {
                int p = fail[now];
                if(!nex[now][i]) {
                    nex[now][i] = nex[p][i];continue;
                }
                fail[nex[now][i]] = nex[p][i];
                q[tail++] = nex[now][i];
            }
        }
    }
    double x,dp[N];
    char s[N];
    int Q,T,pre[N],v[N];
    int main() {
        scanf("%d",&T);
        cnt = 1;
        for(int i = 1; i <= T; ++i) {
            scanf("%s%lf",s,&x);
            insert(s,x);
        }
        build_fail();
        scanf("%d",&Q);
        while(Q--) {
            scanf("%s",s+1);
            int n = strlen(s+1);
            dp[0] = 0;
            int now = 1;
            memset(v,0,sizeof(v));
            memset(pre,0,sizeof(pre));
            for(int i = 1; i <= n; ++i) {
                int id = ID(s[i]);
                now = nex[now][id];
                int tmp = now;
                while(tmp > 1) {
                    if(sum[tmp] != 0) {
                        int t = tmp;
                        double ns = dp[i - len[t]] + len[t]*len[t]*log(sum[t]);
                        if(ns - dp[i] > 0.00001) {
                            dp[i] = ns;
                            pre[i] = i - len[t];
                        }
                        tmp = fail[tmp];
                    }
                    else {
                        tmp = fail[tmp];
                    }
                }
                if(dp[i-1] > dp[i]) {
                    pre[i] = i-1;
                    dp[i] = dp[i-1];
                }
            }
            int tmp = n;
            while(pre[tmp]) {
                v[pre[tmp]] = 1;
                tmp = pre[tmp];
            }
            printf("%.10f
    ",dp[n]);
            for(int i = 1; i <= n; ++i) {
                printf("%c",s[i]);
                if(v[i]) printf(" ");
            }
            printf("
    ");
        }
        return 0;
    }

      

  • 相关阅读:
    盒子垂直水平居中
    Sahi (2) —— https/SSL配置(102 Tutorial)
    Sahi (1) —— 快速入门(101 Tutorial)
    组织分析(1)——介绍
    Java Servlet (1) —— Filter过滤请求与响应
    CAS (8) —— Mac下配置CAS到JBoss EAP 6.4(6.x)的Standalone模式(服务端)
    JBoss Wildfly (1) —— 7.2.0.Final编译
    CAS (7) —— Mac下配置CAS 4.x的JPATicketRegistry(服务端)
    CAS (6) —— Nginx代理模式下浏览器访问CAS服务器网络顺序图详解
    CAS (5) —— Nginx代理模式下浏览器访问CAS服务器配置详解
  • 原文地址:https://www.cnblogs.com/zxhl/p/6848876.html
Copyright © 2011-2022 走看看