后缀自动机
几天不碰SAM,已经对SAM一无所知了QAQ
求x的同构,等价于把x复制一份贴在后面求xx的长度大于len(x)的子串出现次数,注意要判重。
一时智障,把当前SAM匹配的节点的len直接当成真实匹配的len了。。。实际上需要记一个curlen表示当前匹配了多长才科学。
#include<cstdio>
#include<cstring>
#define N 1000005
#define A 28
using namespace std;
namespace runzhe2000
{
char s[N], x[N*2];
int n, L, timer, sum[N];
struct SAM
{
SAM *next[A], *fail;
int len, right, vis;
}mem[N*3], *tot, *null, *last, *root, *tmp[N*3];
SAM* newSAM()
{
SAM *p = ++tot; *p = *null;
return p;
}
void init()
{
null = tot = mem;
for(int i = 0; i < A; i++) null->next[i] = null;
null->fail = null; null->len = null->right = null->vis = 0;
last = root = newSAM();
}
void ins(int v)
{
SAM *p = last, *np = newSAM(); np->len = last->len + 1; np->right = 1; last = np;
for(; p -> next[v] == null && p != null; p = p->fail) p->next[v] = np;
if(p == null) np->fail = root;
else
{
SAM *q = p->next[v];
if(p->len + 1 == q->len) np->fail = q;
else
{
SAM *nq = newSAM(); *nq = *q; nq->len = p->len + 1; nq->right = 0;
q->fail = np->fail = nq;
for(; p->next[v] == q && p != null; p = p->fail) p->next[v] = nq;
}
}
}
int solve(int len)
{
SAM *p = root; ++timer; int ans = 0, curlen = 0;
for(int i = 1; i <= len; i++)
{
int v = x[i] - 'a';
for(; p->next[v] == null && p != null; p = p->fail) curlen = p->fail->len;
if(p->next[v] == null) p = root, curlen = 0;
else p = p -> next[v], curlen++;
for(; p->fail->len >= len/2; p = p->fail) curlen = p->fail->len;
if(curlen >= len/2 && p->vis != timer) p->vis = timer, ans += p->right;
}
return ans;
}
void main()
{
scanf("%s%d",s+1,&n);
L = strlen(s+1); init();
for(int i = 1; i <= L; i++)ins(s[i] - 'a');
for(SAM *p = tot; p != mem; p--) sum[p->len]++;
for(int i = 1; i < N; i++) sum[i] += sum[i-1];
for(SAM *p = tot; p != mem; p--) tmp[sum[p->len]--] = p;
for(int i = tot-mem; i; i--) tmp[i]->fail->right += tmp[i]->right;
for(int _n = 1; _n <= n; _n++)
{
scanf("%s",x+1);
int len = strlen(x+1);
for(int i = 1; i <= len; i++)
x[i+len] = x[i];
len *= 2;
int ans = solve(len);
printf("%d\n",ans);
}
}
}
int main()
{
runzhe2000::main();
}