套了一个后缀数组的模板,求出sa和height数组后,对于每一个后缀字符串,他能产生的不同子串的数量就是len-sa[i]-height[i];
而本题还要求必须包含目的字符tar,这就需要另外一个数组haha,haha[i]表示从第i个字符向后几位找到tar,例如abbabb,tar=a,则haha{0,2,1,0,2,1,0};
而对与每个后缀字符串能产生的包含tar的不通字符串个数就是len-sa[i]-max(height[i],haha[sa[i]]);累加就是了。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<stack>
#include<cstring>
#include<map>
#include<string>
#define LL long long
#define maxn 110000
#define clean(a) memset(a,0,sizeof(a))
using namespace std;
int haha[maxn];
/**************SA模板*******************/
/*
* sa数组和height数组都是从1开始到n结束
*/
//#define clean(a) memset(a,0,sizeof(a))
//#define maxn 110000
char str[maxn];
int _rank[maxn],height[maxn];
int sa[maxn],wa[maxn],wb[maxn],wv[maxn],wss[maxn];
int cmp(int *r,int a,int b,int l)
{
return (r[a]==r[b]&&r[a+l]==r[b+l]);
}
//倍增算法
void da(char *r ,int n,int m)
{
n+=1;
int i, j, p, *x = wa, *y = wb, *t;
//基数排序
for (i = 0; i < m; i++) wss[i] = 0;
for (i = 0; i < n; i++) wss[x[i] = r[i]]++;
for (i = 1; i < m; i++) wss[i] += wss[i - 1];
for (i = n - 1; i >= 0; i--) sa[--wss[x[i]]] = i;
// 在第一次排序以后,_rank数组中的最大值小于p,所以让m=p。整个倍增算法基本写好,代码大约25行。
for (j = 1, p = 1; p < n; j *= 2, m = p)
{
//接下来进行若干次基数排序,在实现的时候,这里有一个小优化。基数排序要分两次,第一次是对第二关键字排序,第二次是对第一关键字排序。对第二关键字排序的结果实际上可以利用上一次求得的sa直接算出,没有必要再算一次
for (p = 0, i = n - j; i < n; i++) y[p++] = i;
for (i = 0; i < n; i++) if (sa[i] >= j) y[p++] = sa[i] - j;
//其中变量j是当前字符串的长度,数组y保存的是对第二关键字排序的结果。然后要对第一关键字进行排序,
for (i = 0; i < n; i++) wv[i] = x[y[i]];
for (i = 0; i < m; i++) wss[i] = 0;
for (i = 0; i < n; i++) wss[wv[i]]++;
for (i = 1; i < m; i++) wss[i] += wss[i - 1];
for (i = n - 1; i >= 0; i--) sa[--wss[wv[i]]] = y[i];
//这样便求出了新的sa值。在求出sa后,下一步是计算_rank值。
for (t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i < n; i++)
x[sa[i]] = cmp(y, sa[i - 1], sa[i], j) ? p - 1 : p++;
}
}
//得到height数组:排名相邻的两个后缀的最长公共前缀
void calheight(char *r,int *sa,int n)
{
int k=0;
for(int i=1;i<=n;i++)
_rank[sa[i]]=i;
for(int i=0;i<n;i++)
{
if(_rank[i]==0)
continue;
k=max(0,k-1);
int j=sa[_rank[i]-1];
while(r[i+k]==r[j+k])
k++;
height[_rank[i]]=k;
}
return;
}
/*********************************/
void gethaha(int len,char tar)
{
memset(haha,0,sizeof(haha));
haha[len]=0;
for(int i=len-1;i>=0;--i)
{
if(str[i]==tar)
haha[i]=0;
else
haha[i]=haha[i+1]+1;
}
}
LL getHaveTarDistinctSubstr(int len)
{
LL ans=0;
for(int i=1;i<=len;i++)
ans+=len-sa[i]-max(height[i],haha[sa[i]]);
return ans;
}
LL getDistinctSubstr(int len)
{
LL ans=0;
for(int i=1;i<=len;i++)
ans+=len-sa[i]-height[i];
return ans;
}
int main()
{
int T,I=1;
scanf("%d",&T);
char tar[12];
while(T--)
{
scanf("%s%s",tar,str);
int len=strlen(str);
da(str,len,128);
// for(int i=1;i<=len;++i)
// cout<<sa[i]<<" ";
// cout<<endl;
calheight(str,sa,len);
// for(int i=1;i<=len;++i)
// cout<<height[i]<<" ";
// cout<<endl;
gethaha(len,tar[0]);
LL ans=getHaveTarDistinctSubstr(len);
printf("Case #%d: %lld\n",I++,ans);
}
return 0;
}