洛谷 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;
}
时间: 2024-09-30 21:58:01

洛谷 P2353 背单词的相关文章

luogu P2353 背单词

二次联通门 : luogu P2353 背单词 一眼看过去, 卧槽,AC自动机板子题 写完后T成SB 卧槽10^6 做个篮子啊 重构思路... 恩..Hash + 莫队... 恶心啊.. 找xxy dalao, AC自动机 + 前缀和 码完WA成SB 去群里找dalao 大佬告诉了我前缀和的正确使用姿势... 然后就依然WA成SB 做个毛线 贴一个AC自动机的30代码 #include <cstdio> #include <cstring> #include <queue&g

AC日记——背单词 洛谷 P2353

背单词 思路: KMP+统计前缀和优化: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 1000005 int n,m,air[maxn][11],len_,len,bi[maxn],fail[maxn]; int lit[11],cnt,ans[maxn]; char ch[maxn],T[maxn]; inline void in(int &now) { char Cget=getchar();now=

[NOIP2001] 提高组 洛谷P1026 统计单词个数

题目描述 给出一个长度不超过200的由小写英文字母组成的字母串(约定;该字串以每行20个字母的方式输入,且保 证每行一定为20个).要求将此字母串分成k份(1<k<=40),且每份中包含的单词个数加起来总数最大(每份中包含的单词可以部分重叠. 当选用一个单词之后,其第一个字母不能再用.例如字符串this中可包含this和is,选用this之后就不能包含th). 单词在给出的一个不超过6个单词的字典中. 要求输出最大的个数. 输入输出格式 输入格式: 每组的第一行有二个正整数(p,k) p表示字

洛谷P2412 查单词 [trie树 RMQ]

题目背景 滚粗了的HansBug在收拾旧英语书,然而他发现了什么奇妙的东西. 题目描述 udp2.T3如果遇到相同的字符串,输出后面的 蒟蒻HansBug在一本英语书里面找到了一个单词表,包含N个单词(每个单词内包含大小写字母).现在他想要找出某一段连续的单词内字典序最大的单词. 输入输出格式 输入格式: 第一行包含两个正整数N.M,分别表示单词个数和询问个数. 接下来N行每行包含一个字符串,仅包含大小写字母,长度不超过15,表示一个单词. 再接下来M行每行包含两个整数x.y,表示求从第x到第y

洛谷 P1026 统计单词个数 区间DP

题目描述 给出一个长度不超过200的由小写英文字母组成的字母串(约定;该字串以每行20个字母的方式输入,且保证每行一定为20个).要求将此字母串分成k份(1<k<=40),且每份中包含的单词个数加起来总数最大(每份中包含的单词可以部分重叠.当选用一个单词之后,其第一个字母不能再用.例如字符串this中可包含this和is,选用this之后就不能包含th). 单词在给出的一个不超过6个单词的字典中. 要求输出最大的个数. 输入输出格式 输入格式: 每组的第一行有二个正整数(p,k) p表示字串的

洛谷 P1308 统计单词数【字符串+模拟】

P1308 统计单词数 题目描述 一般的文本编辑器都有查找单词的功能,该功能可以快速定位特定单词在文章中的位置,有的还能统计出特定单词在文章中出现的次数. 现在,请你编程实现这一功能,具体要求是:给定一个单词,请你输出它在给定的文章中出现的次数和第一次出现的位置.注意:匹配单词时,不区分大小写,但要求完全匹配,即给定单词必须与文章 中的某一独立单词在不区分大小写的情况下完全相同(参见样例1 ),如果给定单词仅是文章中某一单词的一部分则不算匹配(参见样例2 ). 输入输出格式 输入格式: 输入文件

洛谷 P2412 查单词

题目背景 滚粗了的HansBug在收拾旧英语书,然而他发现了什么奇妙的东西. 题目描述 udp2.T3如果遇到相同的字符串,输出后面的 蒟蒻HansBug在一本英语书里面找到了一个单词表,包含N个单词(每个单词内包含大小写字母).现在他想要找出某一段连续的单词内字典序最大的单词. 输入输出格式 输入格式: 第一行包含两个正整数N.M,分别表示单词个数和询问个数. 接下来N行每行包含一个字符串,仅包含大小写字母,长度不超过15,表示一个单词. 再接下来M行每行包含两个整数x.y,表示求从第x到第y

洛谷 P1101 【单词方阵】题解

来先写一下思路: 1.一一枚举开始的位置 2.朝8个方向搜索(其实不如说是递归) 3.在搜索到后标记搜索到了 4.通过标记在搜索完成后再标记哪些地方是"yizhong" 5.输出 严格来说,此题不算是深搜,到不如说是递归,因为只需要往前探路,不需要回溯,下面是代码: #include<iostream>#include<cstdio>using namespace std;int pd,wx[9] = {0,-1,-1,0,1,1,1,0,-1},wy[9] =

洛谷——P1101 单词方阵

https://www.luogu.org/problem/show?pid=1101#sub 题目描述 给一nXn的字母方阵,内可能蕴含多个“yizhong”单词.单词在方阵中是沿着同一方向连续摆放的.摆放可沿着8个方向的任一方向,同一单词摆放时不再改变方向,单词与单词之间[color=red]可以[/color]交叉,因此有可能共用字母.输出时,将不是单词的字母用“*”代替,以突出显示单词.例如: 输入: 8 输出: qyizhong *yizhong gydthkjy gy****** n