Description
给你一个串,问你含某个特定的字符的本质不同子串有多少种。
Solution
设 (f[p]) 表示从结点 (p) 沿着转移边走能到达的不同合法子串有多少种
设题中要求要走的字母为 (c)
对于 (p + c o q),(f[p] leftarrow siz(q))
对于 (p+? o q, ? eq c),(f[p] leftarrow f[q])
其中 (siz(p)) 表示 (p) 点往后可以转移到的本质不同子串数目
#include <bits/stdc++.h>
using namespace std;
const int N = 200005;
struct SAM
{
int len[N], ch[N][26], fa[N], ind, last;
int t[N], a[N], cnt[N], vis[N];
long long f[N];
SAM()
{
ind = last = 1;
}
void init()
{
ind = last = 1;
memset(len,0,sizeof len);
memset(ch,0,sizeof ch);
memset(fa,0,sizeof fa);
memset(t,0,sizeof t);
memset(a,0,sizeof a);
memset(cnt,0,sizeof cnt);
memset(f,0,sizeof f);
memset(vis,0,sizeof vis);
}
inline void extend(int id)
{
int cur = (++ ind), p;
len[cur] = len[last] + 1;
cnt[cur] = 1;
for (p = last; p && !ch[p][id]; p = fa[p]) ch[p][id] = cur;
if (!p) fa[cur] = 1;
else
{
int q = ch[p][id];
if (len[q] == len[p] + 1) fa[cur] = q;
else
{
int tmp = (++ ind);
len[tmp] = len[p] + 1;
for(int i=0; i<26; i++) ch[tmp][i] = ch[q][i];
fa[tmp] = fa[q];
for (; p && ch[p][id] == q; p = fa[p]) ch[p][id] = tmp;
fa[cur] = fa[q] = tmp;
}
}
last = cur;
}
void dfs0(int p,char chr)
{
vis[p]=1;
cnt[p]=1;
for(int i=0;i<26;i++)
{
if(ch[p][i])
{
if(!vis[ch[p][i]])
{
dfs0(ch[p][i],chr);
}
cnt[p]+=cnt[ch[p][i]];
}
}
}
void dfs(int p,char chr)
{
vis[p]=1;
for(int i=0;i<26;i++)
{
if(ch[p][i])
{
if(!vis[ch[p][i]])
{
dfs(ch[p][i],chr);
}
if(i==chr-'a') f[p]+=cnt[ch[p][i]];
else f[p]+=f[ch[p][i]];
}
}
}
void solve(char chr)
{
/*for(int i=ind; i>=1; --i)
{
for(int j=0; j<26; j++)
{
if(ch[i][j])
{
if(j==chr-'a') f[i]+=cnt[ch[i][j]];
else f[i]+=f[ch[i][j]];
}
}
}*/
dfs0(1,chr);
memset(vis,0,sizeof vis);
dfs(1,chr);
}
} sam;
long long solve()
{
ios::sync_with_stdio(false);
string str;
char t;
cin>>str;
t=str[0];
cin>>str;
sam.init();
for(int i=0; i<str.length(); i++)
sam.extend(str[i]-'a');
sam.solve(t);
return sam.f[1];
}
signed main()
{
ios::sync_with_stdio(false);
int t;
cin>>t;
for(int i=1;i<=t;i++)
{
cout<<"Case #"<<i<<": "<<solve()<<endl;
}
}