zoukankan      html  css  js  c++  java
  • CCF 201509-5 最佳文章

    问题描述

      小明最近在研究一门新的语言,叫做Q语言。Q语言单词和文章都可以用且仅用只含有小写英文字母的字符串表示,任何由这些字母组成的字符串也都是一篇合法的Q语言文章。

      在Q语言的所有单词中,小明选出了他认为最重要的n个。使用这些单词,小明可以评价一篇Q语言文章的“重要度”。
      文章“重要度”的定义为:在该文章中,所有重要的Q语言单词出现次数的总和。其中多次出现的单词,不论是否发生包含、重叠等情况,每次出现均计算在内。
      例如,假设n = 2,小明选出的单词是gvagv和agva。在文章gvagvagvagv中,gvagv出现了3次,agva出现了2次,因此这篇文章的重要度为3+2=5。
      现在,小明想知道,一篇由m个字母组成的Q语言文章,重要度最高能达到多少。

    输入格式

      输入的第一行包含两个整数n, m,表示小明选出的单词个数和最终文章包含的字母个数。
      接下来n行,每行包含一个仅由英文小写字母构成的字符串,表示小明选出的这n个单词。

    输出格式

      输出一行一个整数,表示由m个字母组成的Q语言文章中,重要度最高的文章的重要度。

    样例输入

    3 15
    agva
    agvagva
    gvagva

    样例输出

    11

    样例说明

      15个字母组成的重要度最高的文章为gvagvagvagvagva。
      在这篇文章中,agva出现4次,agvagva出现3次,gvagva出现4次,共计4+3+4=11次。

    评测用例规模与约定

      在评测时将使用10个评测用例对你的程序进行评测。
      设s为构成n个重要单词字母的总个数,例如在样例中,s=4+7+6=17;a为构成n个重要单词字母的种类数,例如在样例中,共有3中字母’a’,’g’,’v’,因此a=3。
      评测用例1和2满足2 ≤ n ≤ 3,1500 ≤ m ≤ 2000,s = 40;
      评测用例3和4满足m = 20,2 ≤ a ≤ 3;
      评测用例5、6和7满足2000 ≤ m ≤ 100000;
      评测用例8满足n = 2;
      所有的评测用例满足1 ≤ s ≤ 100,1 ≤ m ≤ 1015,每个单词至少包含1个字母,保证单词中仅出现英文小写字母,输入中不含多余字符,不会出现重复的单词。

    #include<queue>
    #include<stdio.h>
    //#include<iostream>
    //#define debug(x) std::cerr<<#x<<" "<<x<<'
    ';
    const int N=105;
    const int M=1e5+5;
    const int sz=26;
    int n,m,ans,cnt=1,now,p,fail[N],tag[N],tr[N][sz];char s[N<<1];
    bool pre[M][N];int f[M][N];
    #define max(a,b) ((a)>(b)?(a):(b))
    #define son (s[i]-'a')
    void insert(){
        now=1;
        for(int i=0;s[i];i++){
            if(!tr[now][son]) tr[now][son]=++cnt;
            now=tr[now][son];
        }
        tag[now]++;
    }
    std::queue<int>q;
    void acmatch(){
        q.push(1);
        
        for(int i=0;i<sz;i++) tr[0][i]=1;fail[1]=0;
    //    for(int i=0;i<sz;i++) if(tr[1][i]) fail[tr[1][i]]=1;else tr[1][i]=1;
        
        while(!q.empty()){
            now=q.front();q.pop();
            for(int i=0;i<sz;i++){
                if(!tr[now][i]) continue;
                for(p=fail[now];p&&!tr[p][i];p=fail[p]);
                fail[tr[now][i]]=p?tr[p][i]:1;
                q.push(tr[now][i]);
            }
        }
    }
    //void solve(){
    //    p=1;
    //    for(int i=0;s[i];i++){
    //        for(;p&&!tr[p][son];p=fail[p]);
    //        p=p?tr[p][son]:1;
    //        for(int j=p;j;j=fail[j]){
    //            ans+=tag[j];
    ////            tag[j]=-1;
    //        }
    //        // -1 break to faster
    //    }
    //    printf("%d
    ",ans);
    //}
    #undef son
    
    int main(){
    //    freopen("input.txt","r",stdin);
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++) scanf("%s",s),insert();
        acmatch();
        pre[0][1]=1;
        for(int i=1;i<=m;i++){
            for(int j=1;j<=cnt;j++){
                if(pre[i-1][j]){
                    for(int k=0;k<sz;k++){
                        if(!tr[j][k]) tr[j][k]=tr[fail[j]][k];
                        int &sta=tr[j][k];
                        pre[i][sta]=1;
                        int val=0;
                        for(int h=sta;h;h=fail[h]) val+=tag[h];
                        f[i][sta]=max(f[i][sta],f[i-1][j]+val);
                    }
                }
            }
        }
    //    printf("%3d",0);
    //    for(int i=1;i<=cnt;i++) printf("%3d",i);puts("");
    //    for(int i=1;i<=m;i++){
    //        printf("%3d",i);
    //        for(int j=1;j<=cnt;j++){
    //            printf("%3d",f[i][j]);
    //        }
    //        puts("");
    //    }
        for(int i=1;i<=cnt;i++) ans=max(ans,f[m][i]);
        printf("%d
    ",ans);
        return 0;
    }
    60分代码 | AC自动机+朴素DP

     满分代码:

    #include<queue>
    #include<stdio.h>
    #include<memory.h>
    using std::max;
    using std::min;
    typedef long long ll;
    const int N=103,sz=26;
    int n,cnt=1,now,p,fail[N],tag[N],tr[N][sz];char s[N<<1];
    ll m,ans;
    #define son (s[i]-'a')
    void insert(){
        now=1;
        for(int i=0;s[i];i++){
            if(!tr[now][son]) tr[now][son]=++cnt;
            now=tr[now][son];
        }
        tag[now]++;
    }
    std::queue<int>q;
    void acmatch(){
        q.push(1);fail[1]=0;
        for(int i=0;i<sz;i++) tr[0][i]=1;
        while(!q.empty()){
            now=q.front();q.pop();
            tag[now]+=tag[fail[now]];
            for(int i=0;i<sz;i++){
                if(!tr[now][i]) continue;
                for(p=fail[now];p&&!tr[p][i];p=fail[p]);
                fail[tr[now][i]]=p?tr[p][i]:1;
                q.push(tr[now][i]);
            }
        }
    }
    #undef son
    
    struct matrix{
        ll s[N][N];
        matrix(){
            memset(s,-0xf,sizeof s);
        }
    }A;
    matrix operator *(const matrix &a,const matrix &b){
        matrix c;
        for(int i=1;i<=cnt;i++){
            for(int j=1;j<=cnt;j++){
                for(int k=1;k<=cnt;k++){
                    c.s[i][j]=max(c.s[i][j],a.s[i][k]+b.s[k][j]);
                }
            }
        }
        return c;
    }
    matrix fpow(matrix a,ll p){
        matrix res;
        for(int i=1;i<=cnt;i++) res.s[i][i]=0;
        for(;p;p>>=1,a=a*a) if(p&1) res=res*a;
        return res;
    }
    int main(){
        scanf("%d%lld",&n,&m);
        for(int i=0;i<n;i++) scanf("%s",s),insert();
        acmatch();
        for(int i=1,p;i<=cnt;i++){
            for(int j=0;j<sz;j++){
                for(p=i;p&&!tr[p][j];p=fail[p]);
                p=p?tr[p][j]:1;
                A.s[i][p]=tag[p];
            }
        }
        A=fpow(A,m);
        for(int i=1;i<=cnt;i++) ans=max(ans,A.s[1][i]);
        printf("%lld",ans);
        return 0;
    }

     

  • 相关阅读:
    file_get_contents高級用法
    php缓存技术常用函数
    php爬虫的两种思路
    jQuery判断文本框是否为空
    Asp.net 实现图片缩放 无水印(方法二)
    C# winform关于DataGridView的一些操作
    PHP判断访问者手机移动端还是PC端的函数
    本地图片显示在网页
    如何安装 Composer
    国内开源镜像站
  • 原文地址:https://www.cnblogs.com/shenben/p/12653900.html
Copyright © 2011-2022 走看看