时间限制:10000ms
单点时限:1000ms
内存限制:256MB
- 例子输入
-
3 3 tourist petr rng toosimple rg ptr
例子输出
0
1
1
解题思路:
用字典树做的。将第1个字符串集建树,对第2个字符串。去树上匹配。要在树上跳过1个节点的才是满足条件的,于是就递归枚举跳过的节点即可了。
代码:
#include <iostream> #include <cstring> #include <algorithm> #include <cstdio> #include <string> #include <vector> #include <map> #include <set> using namespace std; const int maxn=100000+100; char s[maxn]; const int Max=27; struct node { int sign; int next[Max]; } a[maxn]; set<int> se; int cur=0; void insert(char *s) { int len,ans; int p=0; len=strlen(s); for(int i=0; i<len; i++) { ans=s[i]-'a'; if(a[p].next[ans]!=0) { p=a[p].next[ans]; } else { a[p].next[ans]=++cur; a[cur].sign=0; p=a[p].next[ans]; } } a[p].sign++; } //int ans; int len; void find(int sign,int p,int x) { if(x==len&&sign&&a[p].sign) { // ans+=a[p].sign; se.insert(p); //cout<<ans<<endl; return; } if(sign==0&&x<=len) { for(int i=0; i<26; i++) { if(a[p].next[i]>0) { int tp=a[p].next[i]; find(1,tp,x); } } } if(x<len) { int ne=s[x]-'a'; if(a[p].next[ne]>0) { int tp=a[p].next[ne]; find(sign,tp,x+1); } } } int main() { int n,m; while(~scanf("%d%d",&n,&m)) { for(int i=0; i<maxn; i++) { cur=0; a[i].sign=0; memset(a[i].next,0,sizeof(a[i].next)); } for(int i=0; i<n; i++) { scanf("%s",s); insert(s); } for(int i=0; i<m; i++) { se.clear(); scanf("%s",s); len=strlen(s); //ans=0; find(0,0,0); printf("%d\n",se.size()); } } return 0; }
描写叙述
我们有一个字符串集合S,当中有N个两两不同的字符串。
还有M个询问,每一个询问给出一个字符串w。求有多少S中的字符串能够由w加入恰好一个字母得到。
字母能够加入在包含开头结尾在内的任何位置,比方在"abc"中加入"x",就可能得到"xabc", "axbc", "abxc", "abcx".这4种串。
输入
第一行两个数N和M,表示集合S中字符串的数量和询问的数量。
接下来N行,当中第i行给出S中第i个字符串。
接下来M行,当中第i行给出第i个询问串。
全部字符串仅仅由小写字母构成。
数据范围:
N,M<=10000。
S中字符串长度和<=100000。
全部询问中字符串长度和<=100000。
输出
对每一个询问输出一个数表示答案。