[TJOI2013]单词

[TJOI2013]单词

题目描述

小张最近在忙毕设,所以一直在读论文。一篇论文是由许多单词组成但小张发现一个单词会在论文中出现很多次,他想知道每个单词分别在论文中出现了多少次。

输入输出格式

输入格式:

第一行一个整数N,表示有N个单词。接下来N行每行一个单词,每个单词都由小写字母(a-z)组成。(N≤200)

输出格式:

输出N个整数,第i行的数表示第i个单词在文章中出现了多少次。

本来是最近想用刚学的AC自动机上的,结果出锅了,WA了几次,发现不对劲

先放一下自己的傻吊代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+7;
int m,n,k,cnt;
struct Tree
{
    int ch[27];
    int fail;
    int end;
} AC[N];
string s[N];
struct question
{
    int pos;
    int num;
} ans[N];
void build(string s,int numm)
{
    int l=s.length(),u=0;
    for (int i=0;i<l;i++)
    {
        int c=s[i]-'a';
        if (AC[u].ch[c]==0)  AC[u].ch[c]=++cnt;
        u=AC[u].ch[c]; 
    }
    AC[u].end=numm;
}
void get_fail()
{
    queue<int> que;
    int u=0;
    for (int i=0;i<26;i++)
    if (AC[u].ch[i])
    {
        AC[AC[u].ch[i]].fail=0;
        que.push(AC[u].ch[i]);
    }
    while (!que.empty())
    {
        int x=que.front();que.pop();
        for (int i=0;i<26;i++)
        if (AC[x].ch[i])
        {
            AC[AC[x].ch[i]].fail=AC[AC[x].fail].ch[i];
            que.push(AC[x].ch[i]);
        }
        else AC[x].ch[i]=AC[AC[x].fail].ch[i];
    }
}
void AC_query(string s)
{
    int l=s.length(),u=0;
    for (int i=0;i<l;i++)
    {
        int c=s[i]-'a';
        u=AC[u].ch[c];
        for (int t=u;t;t=AC[t].fail)
        ans[AC[t].end].num++;
    }
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        cin>>s[i];
        int l=s[i].length();
        s[l]='{';
        s[0]+=s[i];
        build(s[i],i);
        ans[i].pos=i;
        ans[i].num=0;
    }
    AC[0].fail=0;
    get_fail();
    AC_query(s[0]);
    for (int i=1;i<=n;i++)    printf("%d
",ans[i].num);
    return 0;
}

后来呢看了眼数据范围,疑,200,直接kmp上吧 

#include<bits/stdc++.h>
using namespace std;
const int N=1e7+7;
int kmp[N],ans[N];
int m,n;
string s[N];
void solve(int k)
{
    memset(kmp,0,sizeof(kmp));
    int j=0,p=0;
    int l1=s[0].length();
    int l2=s[k].length();
    for (int i=2;i<=l2;i++)
    {
        while (j&&s[k][j+1]!=s[k][i]) j=kmp[j];
        if (s[k][j+1]==s[k][i]) j++;
        kmp[i]=j;
    }
    j=0;
    for (int i=1;i<=l1;i++)
    {
        while (j&&s[k][j+1]!=s[0][i]) j=kmp[j];
        if (s[k][j+1]==s[0][i]) j++;
        if (j==l2)
        {
            p++;
            j=kmp[j];
        }
    }
    ans[k]=p;
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        cin>>s[i];
        string ss=s[i];
        ss='#'+ss;
        s[0]+=ss;
        int l=s[i].length();
        for (int j=l;j>=1;j--) s[i][j]=s[i][j-1];
    }
    int l=s[0].length();
    for (int i=l;i>=1;i--) s[0][i]=s[0][i-1];
    for (int i=1;i<=n;i++)
    solve(i);
    for (int i=1;i<=n;i++)
    printf("%d
",ans[i]);
    return 0;
}

最后一个点超时,不过吸一下O2就好了

其实还是用cin读入的事,不过不想改了啊,啦啦啦

慢即是快,细则是能,于小处铸迤逦
原文地址:https://www.cnblogs.com/Hale522520/p/10617228.html