HDU6208 The Dominator of Strings AC自动机 [2017 ACM/ICPC Asia Regional Qingdao Online]

题目链接

Problem Description

Here you have a set of strings. A dominator is a string of the set dominating all strings else. The string S 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自动机建树100000,查询100000
时间是够的,这里先找最长的字符串长len,判断一些是否有多个长度为len不同的字符串,然后建数,跑一次AC自动机就ok
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iomanip>
#include <algorithm>
#include <climits>
#include <cstring>
#include <string>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <vector>
#include <list>
#define rep(i,m,n) for(int i=m;i<=n;i++)
#define rsp(it,s) for(set<int>::iterator it=s.begin();it!=s.end();it++)
const int inf_int = 2e9;
const long long inf_ll = 2e18;
#define inf_add 0x3f3f3f3f
#define MOD 1000000007
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define pi acos(-1.0)
#define pii pair<int,int>
#define Lson L, mid, rt<<1
#define Rson mid+1, R, rt<<1|1
const int maxn=5e2+10;
using namespace std;
typedef  vector<int> vi;
typedef  long long ll;
typedef  unsigned long long  ull;
inline int read(){int ra,fh;char rx;rx=getchar(),ra=0,fh=1;
    while((rx<'0'||rx>'9')&&rx!='-')rx=getchar();if(rx=='-')
        fh=-1,rx=getchar();while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,
                                                  rx=getchar();return ra*fh;}
//#pragma comment(linker, "/STACK:102400000,102400000")
ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);}
ll qpow(ll p,ll q){ll f=1;while(q){if(q&1)f=f*p;p=p*p;q>>=1;}return f;}
int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
const int N = 1e5+1;
const int M = 26;

class Trie
{

public:
    //next数组存储树
    //fail数组存储下一个要匹配的节点号
    //end数组主要是用来标记一个模式串结尾
    int next[N][M],fail[N],end[N];
    int root,L;
    int newnode()
    {
        for(int i = 0;i < M;i++)//每一个节点对应0-128中的任意一个。
            next[L][i] = -1;
        end[L++] = 0;//表示下面没有节点 初始化,如果是记录次数,就赋0 还可以赋任意的数,
        return L-1;
    }
    void init()
    {
        L = 0;
        root = newnode();
    }
    void insert(const char s[])
    {
        int len = strlen(s);
        int now = root;
        for(int i = 0;i < len;i++)
        {
            int k =s[i]-'a';
            if(next[now][k] == -1)
                next[now][k] = newnode();
            now=next[now][k];
        }
//        end[now]=id;//记录当前匹配单词的节点
        end[now]++;//也可以用匹配单词结束后来记录次数
    }

    //BFS求fail
    void build()
    {
        queue<int>Q;
        fail[root] = root;
        //初始化root及其子节点
        for(int i = 0;i < M;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 < M;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(const char buf[])
    {
        int ans=0;
        int len = strlen(buf);
        int now = root;
        bool flag = false;
        for(int i = 0;i < len;i++)
        {
            int k =buf[i]-'a';
            now = next[now][k];
            int temp = now;
            //其会匹配多个模式串
            while(temp != root)
            {
                ans+=end[temp];
                end[temp] = 0;
                temp = fail[temp];
            }
        }
        return ans;
    }
};

char buf[100005];

Trie ac;
int T;
vector<pair<string,int>> ss;
set<string> st;
string s;
int main()
{
//    freopen("data.txt","r",stdin);
    int n,m;
    scanf("%d",&T);
    for(int k=0;k<T;k++)
    {
        ss.clear();
        st.clear();
        int len = 0,maxl = 0;
        scanf("%d",&n);

        for(int i = 0;i <n;i++)
        {
            scanf("%s",buf);
            len = strlen(buf);
            s = buf;
            ss.push_back(make_pair(s,len));
            maxl = max(len,maxl);
        }

        for(int i=0;i<n;i++)
        {
            if(ss[i].second==maxl)
            {
                st.insert(ss[i].first);
            }
            if(st.size()>1)
            {
                 printf("No\n");
                 break;
            }
        }

        if(st.size()>1)
        {
            continue;
        }

        ac.init();
        for(int i=0;i<n;i++)
        {
            ac.insert(ss[i].first.c_str() );
        }

        ac.build();
        s = *st.begin();
//        cout <<ac.query(s.c_str())<<endl;
        if(ac.query(s.c_str())==n)
        {
            printf("%s\n",s.c_str());
        }
        else
        {
            printf("No\n");
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值