其他分享
首页 > 其他分享> > BZOJ5261 Rhyme

BZOJ5261 Rhyme

作者:互联网

Rhyme

<body> Problem 5261. -- Rhyme

5261: Rhyme

Time Limit: 20 Sec  Memory Limit: 256 MB
Submit: 131  Solved: 51
[Submit][Status][Discuss]

Description

由于多次交换邮票没有满足所有人的需求,小Z被赶出了集邮部。无处可去的小Z决定加入音乐部,为了让音乐部的 人注意到自己的才华,小Z想写一首曲子。为了让自己的曲子更好听,小Z找到了一些好听曲子作为模板。曲谱可以 表示成只包含小写字母的字符串,小Z希望自己最终的曲谱中任意一个长度为K的子串都是一个模板的子串。现在小 Z想知道自己的曲谱最长可以是多长,如果可以无限长的话请输出INF。

Input

本题的每个测试点有多组数据,对于每组数据: 第一行两个整数N,K分别表示模板的个数与K值。 接下来N行,每行一个字符串表示一个模板。(只包含'a'~'z') 每组数据字符串总长不超过100000,1≤K≤100000。每个测试点数据不超过10组。

Output

对于每组数据输出一行表示曲子最长可以是多长,如果可以无限长的话输出INF。

Sample Input

1 4
abcabc
1 5
abcabc

Sample Output

INF
6

【样例解释】
第一个样例的曲子可以是"abc"不断循环。
第二个样例的曲子最长是"abcabc"。
【Hint】
对于一个K值来说,任意一个长度小于K的字符串均可行。

HINT

Source

[Submit][Status][Discuss]

HOME Back

题解

参照dummyummy的题解。

可以先看一下这道题 [POI2000]病毒
虽然是个AC自动机,不过思路很像
对于这道题,我们只需要把广义SAM建出来,然后在那些只经过maxlen⩾k的结点的路径中选一个最长的就行了。最后一步可以用拓扑排序来完成
拓扑建边时可以直接向fail连边,而不是把儿子补全(像AC自动机那样ch[u][c]=ch[fail[u]][c]),这样能降低复杂度
最后如果出现环,就输出INF,否则求最长路径,注意特判所有结点的maxlen都小于k的情况,题目最下方有说明



时间复杂度\(O(\sum |s|)\)

#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
    rg T data=0,w=1;rg char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-') w=-w;
    for(;isdigit(ch);ch=getchar()) data=data*10+ch-'0';
    return data*w;
}
template<class T>il T read(rg T&x) {return x=read<T>();}
typedef long long ll;
using namespace std;
typedef pair<int,int> pii;

co int N=2e5+3;
int n,k;
char str[N];
int tot;
int ch[N][26],fa[N],len[N];
vector<pii> g[N];
int ind[N],dis[N];
void clear(){
    for(int i=1;i<=tot+2;++i){
        memset(ch[i],0,sizeof ch[i]);
        g[i].clear(),ind[i]=dis[i]=0;
    }
    tot=1;
}
int extend(int p,int c){
    int last;
    if(ch[p][c]){
        int q=ch[p][c];
        if(len[q]==len[p]+1) last=q;
        else{
            int clone=last=++tot;
            memcpy(ch[clone],ch[q],sizeof ch[q]);
            fa[clone]=fa[q],len[clone]=len[p]+1;
            fa[q]=clone;
            for(;ch[p][c]==q;p=fa[p]) ch[p][c]=clone;
        }
    }
    else{
        int cur=last=++tot;
        len[cur]=len[p]+1;
        for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=cur;
        if(!p) fa[cur]=1;
        else{
            int q=ch[p][c];
            if(len[q]==len[p]+1) fa[cur]=q;
            else{
                int clone=++tot;
                memcpy(ch[clone],ch[q],sizeof ch[q]);
                fa[clone]=fa[q],len[clone]=len[p]+1;
                fa[cur]=fa[q]=clone;
                for(;ch[p][c]==q;p=fa[p]) ch[p][c]=clone;
            }
        }
    }
    return last;
}
void Rhyme(){
    clear();
    for(int i=1;i<=n;++i){
        scanf("%s",str+1);
        int len=strlen(str+1),last=1;
        for(int j=1;j<=len;++j) last=extend(last,str[j]-'a');
    }
    int s=tot+1,t=tot+2;
    for(int i=1;i<=tot;++i){
        if(len[i]==k-1){
            for(int j=0;j<26;++j)if(ch[i][j]) g[i].push_back(pii(ch[i][j],1)),++ind[ch[i][j]];
            g[s].push_back(pii(i,len[i])),++ind[i];
        }
        else if(len[i]>=k){
            for(int j=0;j<26;++j)if(ch[i][j]) g[i].push_back(pii(ch[i][j],1)),++ind[ch[i][j]];
            if(fa[i]&&len[fa[i]]>=k-1) g[i].push_back(pii(fa[i],0)),++ind[fa[i]];
            g[i].push_back(pii(t,0)),++ind[t];
            g[s].push_back(pii(i,len[i])),++ind[i];
        }
    }
    if(!ind[t]) return printf("%d\n",k-1),void();
    int ans=0;
    queue<int> q;q.push(s);
    for(int u;!q.empty();q.pop()){
        u=q.front(),ans=max(ans,dis[u]);
        for(int i=0,v;i<g[u].size();++i){
            v=g[u][i].first,dis[v]=max(dis[v],dis[u]+g[u][i].second);
            if(!--ind[v]) q.push(v);
        }
    }
    for(int i=1;i<=tot;++i)if(ind[i]) return puts("INF"),void();
    printf("%d\n",ans);
}
int main(){
    while(~scanf("%d %d",&n,&k)) Rhyme();
    return 0;
}

标签:ch,曲子,int,Rhyme,rg,ind,INF,BZOJ5261
来源: https://www.cnblogs.com/autoint/p/10899121.html