洛谷 P2353 背单词

 

题目背景

小明对英语一窍不通,令老师十分头疼。于是期末考试前夕,小明被逼着开始背单词……

题目描述

老师给了小明一篇长度为N的英语文章,然后让小明背M个单词。为了确保小明不会在背单词时睡着,老师会向他提Q个问题,每次老师随机选择一个区间L..R,小明要回答在这段文字中他背过的单词总共出现过多少次。

输入输出格式

输入格式:

 

第一行两个整数M、Q如前所述。第二行为英语文章。接下来M行每行一个需要背的单词。接下来Q行每行一个询问,包含两个整数L、R(含端点),即给定的文字区间。

 

输出格式:

 

Q行,对每个询问输出一行表示答案。

 

输入输出样例

输入样例#1:
3 3
abcabcbc
abc
bc
a
1 3
6 7
1 8
输出样例#1:
3
0
7

说明

数据范围:

对于30%的数据,1<=N<=10^3,1<=Q<=10^3

对于60%的数据,1<=N<=10^5,1<=Q<=10^5

对于100%的数据,1<=N<=10^6,1<=M<=10,1<=Q<=10^6,1<=每个单词的长度<=N,1<=L<=R<=N

提示:数据较大,请大家尽量采取高效率的读入输出方法。

 

正解 m次kmp 统计前缀和。

不知为什么的错解:AC自动机,卡了90分钟 。不明白为什么,感觉挺对,也可能是我写得丑。

每次询问取出x~y的子串 跑AC自动机,路过大神帮忙看一下。。(明知不会有大神路过,却依旧恬不知耻)..

屠龙宝刀点击就送

#include <ctype.h>
#include <cstdio>

const int N = 1e6+5;
int que[N],num[N],cnt[N],trie[N][26],fail[N],n,Q,siz=1;
char text[N],a[N];
inline void ins(int k)
{
    int p=1;
    for(char *q=a;*q;++q)
    {
        int id=*q-'a';
        if(!trie[p][id]) trie[p][id]=++siz;
        p=trie[p][id];
    }
    cnt[p]++;
    num[p]=k;
}
inline void Read(int &x)
{
    register char ch=getchar();
    for(x=0;!isdigit(ch);ch=getchar());
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
}
void build()
{
    for(int i=0;i<=25;i++) trie[0][i]=1;
    int l=0,r=0;
    que[++r]=1;
    for(int now=que[++l];l<=r;now=que[++l])
    {
        for(int i=0;i<=25;i++)
        {
            if(trie[now][i])
            {
                if(now==1) fail[trie[now][i]]=1;
                else
                {
                    int tmp=fail[now];
                    for(;tmp;tmp=fail[tmp])
                    {
                        fail[trie[now][i]]=trie[tmp][i];
                        break;
                    }
                    if(!tmp) fail[trie[now][i]]=1;
                }
                que[++r]=trie[now][i]; 
            }
        }
    }
}
int query(int l,int r)
{
    int p=1,ans=0;
    for(int i=l-1;i<r;++i)
    {
        int id=text[i]-'a';
        for(;!trie[p][id];p=fail[p]);
        if(!p) p=1;
        p=trie[p][id];
        int now=p;
        for(;now;now=fail[now])
            if(num[now]) ans+=cnt[now];
    }
    return ans;
}
int main()
{
    Read(n);
    Read(Q);
    scanf("%s",text);
    for(int i=1;i<=n;++i)
    {
        scanf("%s",a);
        ins(i);
    }
    build();
    for(int x,y;Q--;)
    {
        Read(x);
        Read(y);
        printf("%d\n",query(x,y));
    }
    return 0;
}
求说为什么错的AC自动机
#include <cstring>
#include <ctype.h>
#include <cstdio>
const int N = 1e6+5;
inline void read(int &x)
{
    register char ch=getchar();
    for(x=0;!isdigit(ch);ch=getchar());
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
}
int Len,n,Q,los[N],Next[N],sum[N][15];
char text[N],word[N];
void kmp(int k,int l)
{
    int i=0,j=-1;
    Next[i]=j;
    for(;i<l;)
    {
        if(j==-1||word[i]==word[j]) i++,j++,Next[i]=j;
        else j=Next[j];
    }
    i=0,j=0;
    for(;i<Len&&j<l;)
    {
        if(j==-1||text[i]==word[j]) i++,j++;
        else j=Next[j];
        if(j==l) j=Next[j],sum[i][k]++;
        
    }
}
int main()
{
    read(n);
    read(Q);
    scanf("%s",text);
    Len=strlen(text);
    for(int i=1;i<=n;++i)
    {
        scanf("%s",word);
        int len=strlen(word);
        kmp(i,len);
        los[i]=len;
    }
    for(int i=1;i<=Len;++i)
     for(int j=1;j<=n;++j)
     sum[i][j]+=sum[i-1][j];
    for(int x,y,ans;Q--;)
    {
        read(x);
        read(y);
        ans=0;
        for(int i=1;i<=n;i++)
        {
            if(x+los[i]-1<=y)
                ans+=sum[y][i]-sum[x+los[i]-2][i];
        }
        printf("%d\n",ans);
    }
    return 0;
}

 

posted @ 2017-08-17 18:02  杀猪状元  阅读(258)  评论(1编辑  收藏  举报