zoukankan      html  css  js  c++  java
  • poj4052 Hrinity

    pdf题面:传送门

    题目大意:给定一些单词和一个句子,问有多少个单词在句子中出现过,如果一个但单词包含另一个单词,并且两个单词都出现过,那么只算最外层的单词(包含另一个单词的单词).

    分析:这道题如果没有第二个条件的话就和hdu2222是一模一样的题.但是没关系,可以先用hdu2222的方法找出所有出现过的单词,然后每个单词将它的子串给标记.如何找一个串的子串呢?如果一个字符串s[1......n],它的子串必定在s[1......r]和s[l......n]中,也就是在前缀和后缀中,在trie里,找前缀可以利用父亲节点.找后缀可以利用AC自动机的fail指针,这样递归地标记一下就可以了.

    #include <cstdio>
    #include <queue>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 200010,maxm = 5120010;
    char s[maxm],ss[maxm];
    int T,n,cnt,tot = 1,ans;
    bool vis[maxn],tag[maxn],vis2[maxn];
    
    void init()
    {
        n = cnt = ans = 0;
        memset(vis,false,sizeof(vis));
        memset(vis2,false,sizeof(vis2));
        memset(tag,false,sizeof(tag));
    }
    
    struct node
    {
        int tr[30],fail,id,fa;
        void clear()
        {
            memset(tr,0,sizeof(tr));
            fail = id = fa = 0;
        }
    } e[maxn];
    
    void insert(int x)
    {
        int u = 1;
        for (int i = 1; i <= cnt; i++)
        {
            int ch = ss[i] - 'A';
            if (!e[u].tr[ch])
            {
                e[u].tr[ch] = ++tot;
                e[tot].clear();
            }
            int temp = u;
            u = e[u].tr[ch];
            e[u].fa = temp;
        }
        e[u].id = x;
    }
    
    void build()
    {
        queue <int> q;
        for (int i = 0; i < 26; i++)
            e[0].tr[i] = 1;
        q.push(1);
        while (!q.empty())
        {
            int u = q.front();
            q.pop();
            int fail = e[u].fail;
            for (int i = 0; i < 26; i++)
            {
                int y = e[u].tr[i];
                if (y)
                {
                    e[y].fail = e[fail].tr[i];
                    q.push(y);
                }
                else
                    e[u].tr[i] = e[fail].tr[i];
            }
        }
    }
    
    void dfs(int x)
    {
        if (tag[x])
            return;
        tag[x] = 1;
        vis[x] = 0;
        if (e[x].fail)
        dfs(e[x].fail);
        if (e[x].fa)
        dfs(e[x].fa);
    }
    
    bool ischar(char p)
    {
        return p >= 'A' && p <= 'Z';
    }
    
    void getchange()
    {
        int len = strlen(s + 1);
        cnt = 0;
        for (int i = 1; i <= len; i++)
        {
            if (ischar(s[i]))
                ss[++cnt] = s[i];
            else
            {
                i++;
                int res = 0;
                while (s[i] >= '0' && s[i] <= '9')
                {
                    res = res * 10 + s[i] - '0';
                    i++;
                }
                char cc = s[i++];
                while (res)
                {
                    ss[++cnt] = cc;
                    res--;
                }
            }
        }
    }
    
    int main()
    {
        scanf("%d",&T);
        while (T--)
        {
            init();
            e[tot = 1].clear();
            scanf("%d",&n);
            for (int i = 1; i <= n; i++)
            {
                scanf("%s",s + 1);
                getchange();
                insert(i);
            }
            build();
            scanf("%s",s + 1);
            getchange();
            int u = 1;
            for (int i = 1; i <= cnt; i++)
            {
                int ch = ss[i] - 'A';
                while (u && !e[u].tr[ch])
                    u = e[u].fail;
                u = e[u].tr[ch];
                int t = u;
                while (t && !vis2[t])
                {
                    vis2[t] = 1;
                    if (e[t].id)
                        vis[t] = 1;
                    t = e[t].fail;
                }
            }
    
            for (int i = 1; i <= tot; i++)
                if (!tag[i] && vis[i])
                {
                    dfs(e[i].fail);
                    dfs(e[i].fa);
                }
            for (int i = 1; i <= tot; i++)
                if (vis[i])
                    ans++;
            printf("%d
    ",ans);
        }
    
        return 0;
    }
  • 相关阅读:
    JSON序列化时消除空格
    appium测试准备记录
    计算器的单元测试dome
    using关键字在C#中的3种用法
    VxWorks多任务功能
    VS2008与MATLAB R2007a混合编程配置过程
    MATLAB和C语言混合编程-----Matlab7.0 编译器设置
    C++虚函数与纯虚函数用法与区别(转载)
    printf("%f ", 3);输出结果为什么是0.000000(转载)
    浮点型数据在内存中存储的表示(转载)
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8065714.html
Copyright © 2011-2022 走看看