HDU6208 The Dominator of Strings

本文介绍了一种使用AC自动机解决字符串支配者问题的方法。该问题要求从一组字符串中找到一个字符串,使得所有其他字符串都是其子串。文章详细解释了如何通过构建AC自动机并利用最长字符串来高效解决问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

The Dominator of Strings

                                                     Time Limit: 3000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
                                                                           Total Submission(s): 2044    Accepted Submission(s): 738



Problem Description

Here you have a set of strings. A dominator is a string of the set dominating all strings else. The stringS is dominated by T if S is a substring of T.
 

Input

The input contains several test cases and the first line provides the total number of cases.
For each test case, the first line contains an integer N indicating the size of the set.
Each of the following N lines describes a string of the set in lowercase.
The total length of strings in each case has the limit of 100000.
The limit is 30MB for the input file.
 

Output

For each test case, output a dominator if exist, or No if not.
 

Sample Input

3 10 you better worse richer poorer sickness health death faithfulness youbemyweddedwifebetterworsericherpoorersicknesshealthtilldeathdouspartandpledgeyoumyfaithfulness 5 abc cde abcde abcde bcde 3 aaaaa aaaab aaaac
 

Sample Output

youbemyweddedwifebetterworsericherpoorersicknesshealthtilldeathdouspartandpledgeyoumyfaithfulness abcde No


——————————————————————————————————

题目的意思是给出若干个串,判断是否能找出一个串,所有串都是它的字串

思路:AC自动机,首先这个串一定是最长的,所以我们记录下当前最长串,如果处理的串比最长串长那么把之前的最长串扔到字典树里,更新最长串;如果一样长先标记下,如果之后于到更长的的标记清空,最后判标记是否还在,记录重复;否则就把当前串扔到字典树里,最后跑一边AC自动机


#include<bits/stdc++.h>

using namespace std;
const int maxn=100005;

struct Trie
{
    int next[maxn][26],fail[maxn],end[maxn];
    int root,L;
    int newnode()
    {
        memset(next[L],-1,sizeof next[L]);
        end[L++] = 0;
        return L-1;
    }
    void init()
    {
        L = 0;
        root = newnode();
    }
    void insert(char buf[])
    {
        int len = strlen(buf);
        int now = root;
        for(int i = 0; i < len; i++)
        {
            if(next[now][buf[i]-'a'] == -1)
                next[now][buf[i]-'a'] = newnode();
            now = next[now][buf[i]-'a'];
        }
        end[now]++;
    }

    bool findintree(char buf[])
    {
        int len =strlen(buf);
        int now=root;
        int flag=0;
        for(int i=0; i<len; i++)
        {
            if(next[now][buf[i]-'a']!=-1)
            {
                flag=1;
                break;
            }
            now=next[now][buf[i]-'a'];
        }
         return end[now]&&!flag;
    }



void build()
{
    queue<int>Q;
    fail[root] = root;
    for(int i = 0; i < 26; i++)
        if(next[root][i] == -1)
            next[root][i] = root;
        else
        {
            fail[next[root][i]] = root;
            Q.push(next[root][i]);
        }
    while( !Q.empty() )
    {
        int now = Q.front();
        Q.pop();
        for(int i = 0; i < 26; i++)
            if(next[now][i] == -1)
                next[now][i] = next[fail[now]][i];
            else
            {
                fail[next[now][i]]=next[fail[now]][i];
                Q.push(next[now][i]);
            }
    }
}
int query(char buf[])
{
    int len = strlen(buf);
    int now = root;
    int res = 0;
    for(int i = 0; i < len; i++)
    {
        now = next[now][buf[i]-'a'];
        int temp = now;
        while( temp != root )
        {
            res += end[temp];
            end[temp] = 0;
            temp = fail[temp];
        }
    }
    return res;
}
void debug()
{
    printf("id =    ,fail =    ,end =    ,chi = [ a b c d e f g h i j k l m n o p q r s t u v w x y z]\n");
    for(int i = 0; i < L; i++)
    {
        printf("id = %3d,fail = %3d,end = %3d,chi = [",i,fail[i],end[i]);
        for(int j = 0; j < 26; j++)
            printf("%2d",next[i][j]);
        printf("]\n");
    }
}
}ac;
char dic[100005],str[100005];
int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
    int flag=0;
        str[0]='\0';
        ac.init();
        scanf("%d",&n);
        int kk=1;
       for(int i=0;i<n;i++)
        {
            scanf("%s",dic);
            if(strlen(dic)>strlen(str))
            {
                flag=0;
                if(str[0]!='\0')
                ac.insert(str);
                strcpy(str,dic);
            }
            else if(strlen(dic)==strlen(str))
            {
                if(strcmp(dic,str)!=0)
                {
                    flag=1;
                    ac.insert(dic);
                }
                else
                kk++;
            }
            else
            ac.insert(dic);
        }
        ac.build();
        int ans=ac.query(str);
        if(flag) printf("No\n");
        else
        printf("%s\n",ans==n-kk?str:"No");
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值