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<<'\n';
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\n",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\n",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;
}

 

 

posted @ 2020-04-07 15:59  神犇(shenben)  阅读(403)  评论(0编辑  收藏  举报