【SPOJ】MGLAR10 - Growing Strings

Gene and Gina have a particular kind of farm. Instead of growing animals and vegetables, as

it is usually the case in regular farms, they grow strings. A string is a sequence of characters.

Strings have the particularity that, as they grow, they add characters to the left and/or to the

right of themselves, but they never lose characters, nor insert new characters in the middle.

Gene and Gina have a collection of photos of some strings at di?erent times during their growth.

The problem is that the collection is not annotated, so they forgot to which string each photo

belongs to. They want to put together a wall to illustrate strings growing procedures, but they

need your help to ?nd an appropriate sequence of photos.

Each photo illustrates a string. The sequence of photos must be such that if si comes imme-

diately before si+1 in the sequence, then si+1 is a string that may have grown from si (i.e., si

appears as a consecutive substring of si+1). Also, they do not want to use repeated pictures,

so all strings in the sequence must be di?erent.

Given a set of strings representing all available photos, your job is to calculate the size of the

largest sequence they can produce following the guidelines above.

Gene and Gina have a particular kind of farm. Instead of growing animals and vegetables, as it is usually the case in regular farms, they grow strings. A string is a sequence of characters. Strings have the particularity that, as they grow, they add characters to the left and/or to the right of themselves, but they never lose characters, nor insert new characters in the middle.

Gene and Gina have a collection of photos of some strings at di?erent times during their growth. The problem is that the collection is not annotated, so they forgot to which string each photo belongs to. They want to put together a wall to illustrate strings growing procedures, but they need your help to ?nd an appropriate sequence of photos.

Each photo illustrates a string. The sequence of photos must be such that if si comes immediately before si+1 in the sequence, then si+1 is a string that may have grown from si (i.e., si appears as a consecutive substring of si+1). Also, they do not want to use repeated pictures, so all strings in the sequence must be di?erent.

Given a set of strings representing all available photos, your job is to calculate the size of the largest sequence they can produce following the guidelines above.

                --by spoj



大意是有些字符串,从中选一些收尾相接,要求是相邻两串中前串为后串的子串

求最多用多少串

统计以串x为最长串(总母串)的最大方案,再枚举x取max

统计的方法是:

在标记fail指针时,

若x上有is_end标记,则把fail(x)与fa(x)的方案取max再+1作为x的方案;

若x上无is_end标记,虽然理论上不该有方案,但为了递推方便还是把fail(x)与fa(x)的方案取max(不+1)作为方案,不影响结果

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char s[1000010];
struct Trie{
    int ch[26];
}data[1000010];
int tot;
int is_end[1000010],fail[1000010];
int que[10000000];
void work(int );
void Init();
void buildfail();
int main()
{
    int n;
    while(scanf("%d",&n)&&n)
        work(n);
    return 0;
}
void work(int n){
    int i,j,k,len,ans=0;
    Init();
    for(i=1;i<=n;i++){
        scanf("%s",s);
        len=strlen(s);k=0;
        for(j=0;j<len;j++){
            if(!data[k].ch[s[j]-‘a‘])
                data[k].ch[s[j]-‘a‘]=++tot;
            k=data[k].ch[s[j]-‘a‘];
        }
        is_end[k]=1;
    }
    buildfail();
    for(i=0;i<=tot;i++)
        if(ans<is_end[i])
            ans=is_end[i];
    printf("%d\n",ans);
}
void Init(){
    memset(fail,0,sizeof(fail));
    memset(is_end,0,sizeof(is_end));
    memset(data,0,sizeof(data));
    tot=0;
}
void buildfail(){
    int h=0,t=1,i,j,k;
    while(h<t){
        h++;
        for(i=0;i<26;i++)
            if(data[que[h]].ch[i]){
                que[++t]=data[que[h]].ch[i];
                j=fail[que[h]];
                while(1)
                    if(data[j].ch[i]&&data[j].ch[i]!=que[t]){
                        fail[que[t]]=data[j].ch[i];
                        is_end[que[t]]+=is_end[que[h]]>is_end[fail[que[t]]]?is_end[que[h]]:is_end[fail[que[t]]];
                        break;
                    }
                    else{
                        if(!j)break;
                        j=fail[j];
                    }
                if(!fail[que[t]])is_end[que[t]]+=is_end[que[h]];
            }
    }
}

又及,第一次用SPOJ,感觉还不错;

时间: 2025-01-14 16:01:32

【SPOJ】MGLAR10 - Growing Strings的相关文章

【SPOJ】Longest Common Substring II (后缀自动机)

[SPOJ]Longest Common Substring II (后缀自动机) 题面 Vjudge 题意:求若干个串的最长公共子串 题解 对于某一个串构建\(SAM\) 每个串依次进行匹配 同时记录\(f[i]\)表示走到了\(i\)节点 能够匹配上的最长公共子串的长度 当然,每个串的\(f[i]\)可以更新\(f[i.parent]\) 所以需要拓扑排序 对于每个串求出每个节点的最长匹配 然后对他们取\(min\),表示某个节点大家都能匹配的最长长度 最后对于所有点的值都取个\(max\)

【SPOJ】Distinct Substrings(后缀自动机)

[SPOJ]Distinct Substrings(后缀自动机) 题面 Vjudge 题意:求一个串的不同子串的数量 题解 对于这个串构建后缀自动机之后 我们知道每个串出现的次数就是\(right/endpos\)集合的大小 但是实际上我们没有任何必要减去不合法的数量 我们只需要累加每个节点表示的合法子串的数量即可 这个值等于\(longest-shortest+1=longest-parent.longest\) #include<iostream> #include<cstdio&g

【SPOJ】Longest Common Substring(后缀自动机)

[SPOJ]Longest Common Substring(后缀自动机) 题面 Vjudge 题意:求两个串的最长公共子串 题解 \(SA\)的做法很简单 不再赘述 对于一个串构建\(SAM\) 另外一个串在\(SAM\)上不断匹配 最后计算答案就好了 匹配方法: 如果\(trans(s,c)\)存在 直接沿着\(trans\)走就行,同时\(cnt++\) 否则沿着\(parent\)往上跳 如果存在\(trans(now,c),cnt=now.longest+1\) 否则,如果不存在可行的

【SPOJ】NUMOFPAL - Number of Palindromes(Manacher,回文树)

[SPOJ]NUMOFPAL - Number of Palindromes(Manacher,回文树) 题面 洛谷 求一个串中包含几个回文串 题解 Manacher傻逼题 只是用回文树写写而已.. #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<

【SPOJ】QTREE6(Link-Cut-Tree)

[SPOJ]QTREE6(Link-Cut-Tree) 题面 Vjudge 题解 很神奇的一道题目 我们发现点有黑白两种,又是动态加边/删边 不难想到\(LCT\) 最爆力的做法,显然是每次修改单点颜色的时候 暴力修改当前点和它的父亲以及儿子之间的连边状态 但是这样显然是假的(菊花树了解一下) 怎么优化呢? 对于每次操作,我们考虑如何只修改一次. 对于树上的一个结点,如果只修改一次,显然是修改和其父亲的状态. 那么,我们在考虑\(LCT\)的连边操作的时候, 如果当前点变色,那么就只修改和它父亲

【SPOJ】QTREE7(Link-Cut Tree)

[SPOJ]QTREE7(Link-Cut Tree) 题面 洛谷 Vjudge 题解 和QTREE6的本质是一样的:维护同色联通块 那么,QTREE6同理,对于两种颜色分别维护一棵\(LCT\) 每次只修改和它父亲的连边. 考虑如何维护最大值 因为每次\(access\)会删去一个数,所以我们肯定不能够只维护最大值. 因此,对于每一个节点,额外维护一个\(multiset\)(当然,可删堆,\(map\)之类的也行) 每次用\(multiset\)维护虚子树的最值,拿过去更新即可. 最后的答案

【SPOJ】Longest Common Substring

[SPOJ]Longest Common Substring 求两个字符串的最长公共子串 对一个串建好后缀自动机然后暴力跑一下 废话 讲一下怎么跑吧 从第一个字符开始遍历,遍历不到了再沿着\(parents\)走看能否找到出路,走到某个点时,统计一下走过了多少点然后更新答案 来说说这样做的正确性: 遍历是肯定的, PAM 从根节点出发的任意路径都表示一个子串 沿着\(parents\)边往后走,保证贪心情况下维护最长公共子串寻找出路 注意这里是统计走过了多少点更新答案,不能直接通过\(len\)

【SPOJ】Longest Common Substring II

[SPOJ]Longest Common Substring II 多个字符串求最长公共子串 还是将一个子串建SAM,其他字符串全部跑一边,记录每个点的最大贡献 由于是所有串,要对每个点每个字符串跑完后去最小值才是每个点的最终贡献 #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm

【SPOJ】1812. Longest Common Substring II(后缀自动机)

http://www.spoj.com/problems/LCS2/ 发现了我原来对sam的理解的一个坑233 本题容易看出就是将所有匹配长度记录在状态上然后取min后再对所有状态取max. 但是不要忘记了一点:更新parent树的祖先. 为什么呢?首先如果子树被匹配过了,那么长度一定大于任意祖先匹配的长度(甚至有些祖先匹配长度为0!为什么呢,因为我们在匹配的过程中,只是找到一个子串,可能还遗漏了祖先没有匹配到,这样导致了祖先的记录值为0,那么在对对应状态去min的时候会取到0,这样就wa了.而