2782: [HNOI2006]最短母串

2782: [HNOI2006]最短母串

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 3  Solved: 2
[Submit][Status][Web Board]

Description

给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串。

Input

第一行是一个正整数n(n<=12),表示给定的字符串的个数。以下的n行,每行有一个全由大写字母组成的字符串。每个字符串的长度不超过50.

Output

只有一行,为找到的最短的字符串T。在保证最短的前提下,如果有多个字符串都满足要求,那么必须输出按字典序排列的第一个。

Sample Input

2
ABCD
BCDABC

Sample Output

ABCDABC

HINT

Source

题解:

  

  首先我的思路十分傻叉,是f[i][j][k]f[i][j][k]表示长度为ii,在自动机上的节点为jj,包含子串的状态为kk可不可能.但这样复杂度直接爆炸.

  但是我们可以令f[i][j]f[i][j]表示在自动机上的节点为ii,包含子串的状态为jj时的最短长度.

  这样我们就转化成了边权均为1的单源最短路,BFS就行了.

  若按照字母字典序从小到大的顺序进行BFS,得出的就是字典序最小的答案了.

  (有点卡内存)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int inf=1e9;
struct Node{
    int fail,ch[26],val;
    void clear(){
        fail=val=0;
        memset(ch,0,sizeof(ch));
    }
}tr[605];
int sz;
int bin[20],n;
void insert(char *s,int val){
    int u=0,len=strlen(s);
    for(int i=0;i<len;i++){
        int c=s[i]-‘A‘;
        if(!tr[u].ch[c]){
            tr[u].ch[c]=++sz;
            tr[sz].clear();
        }
        u=tr[u].ch[c];
    }
    tr[u].val|=bin[val];
}
void build(){
    queue<int>q;q.push(0);
    while(!q.empty()){
        int u=q.front();q.pop();
        for(int i=0;i<26;i++){
            if(tr[u].ch[i]){
                int v=tr[u].ch[i];
                if(u)tr[v].fail=tr[tr[u].fail].ch[i];
                q.push(v);
            }else tr[u].ch[i]=tr[tr[u].fail].ch[i];
        }
    }
}
int fromu[605][4100],froms[605][4100];
bool vis[605][4100];
void print(int u,int s){
    if(!u)return;
    print(fromu[u][s],froms[u][s]);
    for(int i=0;i<26;i++){
        int v=tr[fromu[u][s]].ch[i],t=froms[u][s];
        for(int p=v;p;p=tr[p].fail)
        t|=tr[p].val;
        if(v==u&&t==s){
            putchar(‘A‘+i);
            break;
        }
    }
}
void bfs(){
    queue<int>q1,q2;
    q1.push(0);q2.push(0);
    vis[0][0]=1;
    while(!q1.empty()){
        int u=q1.front(),s=q2.front();q1.pop();q2.pop();
        for(int i=0;i<26;i++){
            int v=tr[u].ch[i],t=s;
            for(int p=v;p;p=tr[p].fail)
            t|=tr[p].val;
            if(!vis[v][t]){
                vis[v][t]=1;
                q1.push(v);q2.push(t);
                fromu[v][t]=u;
                froms[v][t]=s;
                if(t==bin[n+1]-1){
                    print(v,t);
                    return;
                }
            }
        }
    }
}
char s[55];
int main(){
    scanf("%d",&n);
    tr[sz=0].clear();
    bin[1]=1;
    for(int i=2;i<20;i++)bin[i]=bin[i-1]<<1;
    for(int i=1;i<=n;i++){
        scanf("%s",s);
        insert(s,i);
    }
    build();
    bfs();
    return 0;
}

时间: 2024-10-05 23:54:43

2782: [HNOI2006]最短母串的相关文章

BZOJ 1195: [HNOI2006]最短母串

1195: [HNOI2006]最短母串 Time Limit: 10 Sec  Memory Limit: 32 MBSubmit: 1346  Solved: 450[Submit][Status][Discuss] Description 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串. Input 第一行是一个正整数n(n<=12),表示给定的字符串的个数.以下的n行,每行有一个全由大写字母组成的字符串.每个字符串

bzoj 1195: [HNOI2006]最短母串 爆搜

1195: [HNOI2006]最短母串 Time Limit: 10 Sec  Memory Limit: 32 MBSubmit: 894  Solved: 288[Submit][Status][Discuss] Description 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串. Input 第一行是一个正整数n(n<=12),表示给定的字符串的个数.以下的n行,每行有一个全由大写字母组成的字符串.每个字符串的

Bzoj1195 [HNOI2006]最短母串 [AC自动机]

Time Limit: 10 Sec  Memory Limit: 32 MBSubmit: 1304  Solved: 439 Description 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串. Input 第一行是一个正整数n(n<=12),表示给定的字符串的个数.以下的n行,每行有一个全由大写字母组成的字符串.每个字符串的长度不超过50. Output 只有一行,为找到的最短的字符串T.在保证最短的前提下,如果

[BZOJ1195]最短母串

1195: [HNOI2006]最短母串 Time Limit: 10 Sec  Memory Limit: 32 MB Description 给定n个字符串(S1,S2,?,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,?,Sn)都是T的子串. Input 第一行是一个正整数n(n<=12),表示给定的字符串的个数.以下的n行,每行有一个全由大写字母组成的字符串.每个字符串的长度不超过50. Output 只有一行,为找到的最短的字符串T.在保证最短的前提下,如果有多个字

最短母串

Ac_automaton的与状压的结合. 看题解说是Ac_automaton上的dp,但是实际上没有十分明显的转移过程,仅仅使用状压的方式记录某个串是否被选择过了(当然有建完Ac_automation然后跑纯状压dp的解法). 首先建立Ac_automaton(Trie图),额外维护一个sta数组,该数组为一个二进制表示数组,‘1’表示该串出现过,‘0’表示该串为出现过.这个信息需要在insert与generate(build)过程中统计,然而有趣的是,网上的大部分题解仅有由fail更新当前节点

【题解】最短母串

题目大意 ??有\(n\)个字符串\(s_1,s_2,\dots,s_n\),求一个最短的字符串\(S\),使这\(n\)个字符串都是\(S\)的子串. ? 题解 ??我们先对这\(n\)个字符串建AC自动机,这里我们对于Trie上的结点\(i\),定义一个状态\(state_i\),表示第\(i\)个结点对应的字符串,包含的题目中给出的哪些字符串. ??我们可以从Trie上的根节点,按照字典序BFS,我们用\(f\)表示当前经过的所有结点的包含的所有字符串,显然,当\(f\)包含所有字符串时,

python 字符串函数find功能拓展——查找母串内所有子串的位置

前言 我们知道,字符串内置了很多功能的处理函数,其中,find.index函数都可以接受一个参数意义是作为目标子串,而返回母串中从左到右遍历时子串第一次出现的索引值(每一次调用都是从头开始,没有记忆),如果查询不到返回-1. 如下面的例子: 如果,子串不在母串中出现,则find函数返回-1,而index方法返回ValueError错误,这也是两者的区别,接上例: 深入 rindex rfind函数:功能类似,把母串从右向左遍历,找到子串第一次出现的位置,也没有记忆性. 后续 我编写了一个函数,实

dp-LCS(递归输出最短合串)

Problem Description The company "21st Century Fruits" has specialized in creating new sorts of fruits by transferring genes from one fruit into the genome of another one. Most times this method doesn't work, but sometimes, in very rare cases, a

2017&quot;百度之星&quot;程序设计大赛 - 资格赛 寻找母串

Problem Description 对于一个串S,当它同时满足如下条件时,它就是一个01偏串: 1.只由0和1两种符组成: 2.在S的每一个前缀中,0的个数不超过1的个数: 3.S中0的个数和1的个数相等. 现在给定01偏串S,请计算一下S在所有长度为n的01偏串中作为子串出现的次数的总和. 由于结果比较大,结果对1e9+7取余后输出. 样例解释: 在第二个样例中,长度为4的偏串共两个1010,1100.10在1010中出现了两次,在1100中出现了1次.所以答案是3. Input 第一行给