半日份七夕节的礼物。(连续越界打击,tle打击,最后玄学ac
问题所在:
- 越界:结点数组开小了。
- tle:问题在于初始化ch结点数组时,只初始化了ch[0]。
- 空间超限:就是maxm太大了
思路就是建Trie树,然后建立fail数组,继而查找。可查看Trie+AC自动机
建树:
void ins(char *s) //s是模式串
{
int l = strlen(s),cur = 0; //cur是结点所在标序
for(int i=0;i<l;++i)
{
int v = s[i] - 'a';
if(!ch[cur][v]) ch[cur][v] = ++pc; //pc是结点标序,一直累加
cur = ch[cur][v];
}
flag[cur]++; //是否是结尾,即是否构成单词,和该单词出现次数
}
GetFail数组:(都说类似KMP,把线性递归改成了bfs)
void getfail()
{
queue<int> q;
f[0] = 0;
for(int c=0;c<alpha;++c) //alpha是26
{
int u = ch[0][c];
if(u) {
f[u] = 0;q.push(u);
}
}
while(!q.empty())
{
int r = q.front();q.pop();
for(int c=0;c<alpha;++c)
{
int u = ch[r][c];
/* if(!u) //这三行“麻竹”,蓝书说实践时可以将下行的这么写,
{
ch[r][c] = ch[f[r]][c]; continue; //从而没了复杂的失配过程,
}
*/ //可删去find()里的失配转移,将转移一视同仁。
if(!u) continue;
q.push(u);
int v = f[r];
while(v && !ch[v][c]) v = f[v]; //类同KMP
f[u] = ch[v][c];
}
}
}
find函数及统计单词出现个数:
int find(char *str)
{
int n =strlen(str);
int j = 0,cnt = 0;
for(int i=0;i<n;++i)
{
int c = str[i] - 'a';
while(j && !ch[j][c]) j = f[j]; //这行就是上面getfail所说的可删去部分
j = ch[j][c];
int temp = j; //不能改变j的值
while(temp != 0){
cnt += flag[temp];
flag[temp] = 0; //记得清除,避免重复计算
temp = f[temp];
}
}
return cnt;
}
完整代码:
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int maxn = 60,alpha = 26,maxt = 1e6+10,maxm = 5*1e5;
int ch[maxm][alpha],pc,f[maxm];
char s[maxn],str[maxt];
int flag[maxm];
void ins(char *s)
{
int l = strlen(s),cur = 0;
for(int i=0;i<l;++i)
{
int v = s[i] - 'a';
if(!ch[cur][v]) ch[cur][v] = ++pc;
cur = ch[cur][v];
}
flag[cur]++;
}
void getfail()
{
queue<int> q;
f[0] = 0;
for(int c=0;c<alpha;++c)
{
int u = ch[0][c];
if(u) {
f[u] = 0;q.push(u);
}
}
while(!q.empty())
{
int r = q.front();q.pop();
for(int c=0;c<alpha;++c)
{
int u = ch[r][c];
/* if(!u){
ch[r][c] = ch[f[r]][c]; continue;
}*/
if(!u) continue;
q.push(u);
int v = f[r];
while(v && !ch[v][c]) v = f[v];
f[u] = ch[v][c];
}
}
}
int find(char *str)
{
int n =strlen(str);
int j = 0,cnt = 0;
for(int i=0;i<n;++i)
{
int c = str[i] - 'a';
while(j && !ch[j][c]) j = f[j];
j = ch[j][c];
int temp = j;
while(temp != 0){
cnt += flag[temp];
flag[temp] = 0;
temp = f[temp];
}
}
return cnt;
}
int main()
{
int t,n;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=0;i<n;++i)
{
scanf(" %s",s);
ins(s);
}
getfail();
scanf(" %s",str);
int ans = find(str);
printf("%d\n",ans);
pc = 0;
memset(flag,0,sizeof(flag));
memset(ch,0,sizeof(ch));
}
return 0;
}