题目大意:
就是现在有N个( N <= 10^5) 个字符串(长度不超过6),问在字符串A (长度不超过10^5) 中对应的那N个串都出现了多少次,每个串对应的计数方式可以不一样,type 为0的串可以重叠计数,而type = 1的不能重叠,求问每个串在字符串A中对应的出现的次数,输入的字符串只包含小写字母
大致思路:
首先这题要注意多个字符串可以出现一样的串,计数方式可以不同,不顾哦总体来说还是简单的,只需要记录当前节点的上一次有效计数时是在串A的第几个位置就可以判断当前是否会和上一次的计数有重合部分。
代码如下:
Result : Accepted Memory : 75896 KB Time : 640 ms
/*
* Author: Gatevin
* Created Time: 2014/11/22 18:47:10
* File Name: Kagome.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;
char s[100010];
char ts[8];
int type[100010];//询问类型
int n;
int cas;
struct Trie
{
int next[600010][26], fail[600010], deep[600010], end[600010], last[600010], cnt[600010][2];
/*
* deep[i]表示节点编号为i的点是子串的第几个
* end[id]表示第id个查询的串是在Trie树中的哪个个节点结尾
* last[i]表示编号为i的节点所代表的串上一次计数是在A串的哪个位置结尾
* cnt[i][j]表示计数类型为j,Trie编号为i节点字符串的出现次数
*/
int L, root;
int newnode()
{
for(int i = 0; i < 26; i++)
next[L][i] = -1;
L++;
return L - 1;
}
void init()
{
L = 0;
root = newnode();
deep[root] = 0;
return;
}
void insert(char* in, int id)
{
int now = root;
int dep = 0;
for(; *in; in++)
{
if(next[now][*in - 'a'] == -1)
next[now][*in - 'a'] = newnode();
now = next[now][*in - 'a'];
deep[now] = ++dep;
}
end[id] = now;
return;
}
void build()
{
queue <int> Q;
fail[root] = root;
Q.push(root);
while(!Q.empty())
{
int now = Q.front();
Q.pop();
for(int i = 0; i < 26; i++)
if(next[now][i] == -1)
next[now][i] = now == root ? root : next[fail[now]][i];
else
{
fail[next[now][i]] = now == root ? root : next[fail[now]][i];
Q.push(next[now][i]);
}
}
return;
}
void solve()
{
for(int i = 0; i < L; i++)
{
last[i] = -1;
cnt[i][0]= cnt[i][1] = 0;
}
int len = strlen(s);
int now = root;
for(int i = 0; i < len; i++)
{
now = next[now][s[i] - 'a'];
int tmp = now;
while(tmp != root)
{
cnt[tmp][0]++;
if(deep[tmp] + last[tmp] <= i)//判断是否重叠
{
cnt[tmp][1]++;
last[tmp] = i;
}
tmp = fail[tmp];
}
}
printf("Case %d\n", cas);
for(int i = 1; i <= n; i++)
{
printf("%d\n", cnt[end[i]][type[i]]);
}
printf("\n");
}
};
Trie AC;
int main()
{
cas = 0;
while(scanf("%s", s) != EOF)
{
cas++;
scanf("%d", &n);
AC.init();
for(int i = 1; i <= n; i++)
{
scanf("%d %s", type + i, ts);
AC.insert(ts, i);
}
AC.build();
AC.solve();
}
return 0;
}