洛谷 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; }
#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; }
我们都在命运之湖上荡舟划桨,波浪起伏着而我们无法逃脱孤航。但是假使我们迷失了方向,波浪将指引我们穿越另一天的曙光。