【多题合集】AC自动机练习,被HDU支配的恐惧

写正文之前容我吐槽一发:HDU真坑爹啊!我在这上面交了两天不到的题什么错误都有啊!CE啊!变量名别整奇怪啊!万能库不认识啊!G++和C++不一样啊!PE啊,你最后一行给我少了个回车这是不行的啊!OLE啊!你说我手贱输出那么多值干嘛啊!卡你内存卡你初始化卡你字符串函数卡巴斯基啊!英文题面啊!ACM好厉害呀!去做个题读题时间最长啊!多组数据啊!初始化你也要想好那些需要啊!看不清楚就快滚蛋吧!地球太危险了你还是回火星吧!

传送门-P2222
题意:给一些子串和一个总串,问有多少个子串在总串中出现过
思路:AC自动机裸题,不想说什么
注意:千万别用memset!字符串取长度时先赋值到变量上!
代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
int t,n,tot,root=1;
char s[53],ch[1000003];
int fail[500003],num[500003],trie[500003][26];
queue<int> q;
inline void insert(char s[])
{
    int now=root,len=strlen(s);
    for (int i=0;i<len;i++)
    {
        if (!trie[now][s[i]-'a']) trie[now][s[i]-'a']=++tot;
        now=trie[now][s[i]-'a'];
    }
    num[now]++;
}
inline void build()
{
    int now=root;
    q.push(root);
    while (!q.empty())
    {
        now=q.front();
        q.pop();
        for (int i=0;i<26;i++)
        if (trie[now][i])
        {
            int tmp=fail[now];
            while (!trie[tmp][i]&&tmp) tmp=fail[tmp];
            if (now!=root&&tmp)fail[trie[now][i]]=trie[tmp][i];
            else fail[trie[now][i]]=root;
            q.push(trie[now][i]);
        }
    }
}
int main()
{
    scanf("%d",&t);
    while (t--)
    {
        tot=1;
        scanf("%d",&n);
        while (n--)
        {
            scanf("%s",s);
            insert(s);
        }
        build();
        scanf("%s",ch);
        int now=root,ans=0,len=strlen(ch);
        for (int i=0;i<len;i++)
        {
            while (!trie[now][ch[i]-'a']&&now) now=fail[now];
            if (!now) now=root;
            else now=trie[now][ch[i]-'a'];
            int tmp=now;
            while (tmp!=root)
            {
                ans+=num[tmp];
                num[tmp]=0;
                tmp=fail[tmp];
            }
        }
        printf("%d\n",ans);
        for (int i=1;i<=tot;i++)
        {
            num[i]=fail[i]=0;
            for (int j=0;j<26;j++) trie[i][j]=0;
        }
    }
}

传送门-P2896
题意:是中文题面终于不用找翻译了哈哈
思路:记录编号与总数
注意:依旧卡内存,把你能想象到的技巧全用上吧!(为什么ASCLL不是0-255呢……)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
int n,m,tot=1,root=1,ans;
int trie[100010][128],fail[100010],num[100010];
char s[10010];
bool flag[510];
queue <int> q;
void insert(int x,char s[])
{
    int len=strlen(s),now=root;
    for (int i=0;i<len;i++)
    {
        if (!trie[now][s[i]]) trie[now][s[i]]=++tot;
        now=trie[now][s[i]];
    }
    num[now]=x;
}
void build()
{
    int now=root,tmp;
    q.push(now);
    while (!q.empty())
    {
        now=q.front();
        q.pop();
        for (int i=0;i<=127;i++)
        if (trie[now][i])
        {
            tmp=fail[now];
            while (tmp&&!trie[tmp][i]) tmp=fail[tmp];
            if (now!=root&&tmp) fail[trie[now][i]]=trie[tmp][i];
            else fail[trie[now][i]]=root;
            q.push(trie[now][i]);
        }
    }
}
bool solve(int x)
{
    scanf("%s",s);
    int tmp,len=strlen(s),now=root,cnt=0;
    memset(flag,0,sizeof(flag));
    for (int i=0;i<len;i++)
    {
        while (now&&!trie[now][s[i]]) now=fail[now];
        if (!now) now=root;
        else now=trie[now][s[i]];
        tmp=now;
        while (tmp!=root)
        {
            if (num[tmp]) cnt++,flag[num[tmp]]=1;
            tmp=fail[tmp];
        }
    }
    if (!cnt) return 0;
    printf("web %d:",x);
    for (int i=1;i<=n;i++)
    if (flag[i]) printf(" %d",i);
    puts("");
    return 1;
}
main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    scanf("%s",s),
    insert(i,s);
    build();
    scanf("%d",&m);
    for (int i=1;i<=m;i++)
    if (solve(i)) ans++;
    printf("total: %d\n",ans);
}

传送门-P3065
题意:中文
思路:基本与上面相同,当主串中当前位置不是大写字母时可以直接跳回root
注意:多组数据!多组数据!题面中没说,但是多组数据!
代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define pd(i) (i>='A'&&i<='Z')
using namespace std;
int n,root=1,tot=1;
char ch[1002][52],s[2000002];
int ans[50010],num[50010],fail[50010],trie[50010][26];
queue <int> q;
void insert(int x,char s[])
{
    int now=root,len=strlen(s);
    for (int i=0;i<len;i++)
    {
        if (!trie[now][s[i]-'A']) trie[now][s[i]-'A']=++tot;
        now=trie[now][s[i]-'A'];
    }
    num[now]=x;
}
void build()
{
    int now=root,tmp;
    q.push(now);
    while (!q.empty())
    {
        now=q.front();
        q.pop();
        for (int i=0;i<26;i++)
        if (trie[now][i])
        {
            tmp=fail[now];
            while (tmp&&!trie[tmp][i]) tmp=fail[tmp];
            if (now!=root&&tmp) fail[trie[now][i]]=trie[tmp][i];
            else fail[trie[now][i]]=root;
            q.push(trie[now][i]);
        }
    }
}
void work()
{
    tot=1;
    memset(ans,0,sizeof(ans));
    memset(trie,0,sizeof(trie));
    memset(num,0,sizeof(num));
    for (int i=1;i<=n;i++)
    scanf("%s",ch[i]),
    insert(i,ch[i]);
    build();
    scanf("%s",s);
    int now=root,tmp,len=strlen(s);
    for (int i=0;i<len;i++)
    {
        if (!pd(s[i])) {now=root;continue;}
        while (now&&!trie[now][s[i]-'A']) now=fail[now];
        if (!now) now=root;
        else now=trie[now][s[i]-'A'];
        tmp=now;
        while (tmp!=root)
        {
            if (num[tmp]) ans[num[tmp]]++;
            tmp=fail[tmp];
        }
    }
    for (int i=1;i<=n;i++)
    if (ans[i])
        printf("%s: %d\n",ch[i],ans[i]);
}
main()
{
    while (scanf("%d",&n)!=EOF)
    work();
}

本来还想再放一道ZOJ上的题,但是它交不上!不是CE、RE,而是真的交不上!一交就出错!弃疗的我打了个A+B上用这个问题交了上去却能交上!!!

你可能感兴趣的:(【多题合集】AC自动机练习,被HDU支配的恐惧)