http://acm.hdu.edu.cn/showproblem.php?pid=5769
题意:给你一个串,问你含某个特定的字符的不同子串有多少种。。
思路:使用后缀数组。。很久之前看过做过几个模板水题。。以为自己做不到这么高深的题目。。结果这次就卡了,想hash莽一下发现很不科学,就放弃了。。看来后缀数组也已经是标配了。。赶紧再补充补充自己。。
首先退一步讲,后缀数组如何求不同子串个数。。。其实就是利用排序的性质来解决。。假设我们得到了sa和height。。那么我们来枚举每一个后缀串对于答案的贡献。。显然不考虑重复肯定是len-sa[ i ]。。也就是总长度减去现在的位置,这个很好理解。。那么如何去除重复呢?利用排序的性质和height的意义。。也就是排序好的相邻的最长公共前缀。。那么我们就可以知道有多少是重复的,这样就是len-sa[ i ]-height[ i ]。。到这里问题基本就解决了。
回到这个题目,要包含某个特定的字符,其实如果知道每个后缀串要做出贡献至少要多长就可以。。如果知道了,套用上面的就好啦~
PS。后缀数组的原理还是不是很懂。。不过重在应用。。慢慢学习。。
代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN=200010;
int t1[MAXN],t2[MAXN],c[MAXN];//求SA数组需要的中间变量,不需要赋值
bool cmp(int *r,int a,int b,int l){
return r[a] == r[b] && r[a+l] == r[b+l];
}
void da(int str[],int sa[],int ran[],int height[],int n,int m){
n++;
int i, j, p, *x = t1, *y = t2;
for(i = 0; i < m; i++)c[i] = 0;
for(i = 0; i < n; i++)c[x[i] = str[i]]++;
for(i = 1; i < m; i++)c[i] += c[i-1];
for(i = n-1; i >= 0; i--)sa[--c[x[i]]] = i;
for(j = 1; j <= n; j <<= 1){
p = 0;
for(i = n-j; i < n; i++)y[p++] = i;//后面的j个数第二关键字为空的最小
for(i = 0; i < n; i++)if(sa[i] >= j)y[p++] = sa[i] - j;
for(i = 0; i < m; i++)c[i] = 0;
for(i = 0; i < n; i++)c[x[y[i]]]++;
for(i = 1; i < m; i++)c[i] += c[i-1];
for(i = n-1; i >= 0; i--)sa[--c[x[y[i]]]] = y[i];
swap(x,y);
p = 1;
x[sa[0]] = 0;
for(i = 1; i < n; i++) x[sa[i]] = cmp(y,sa[i-1],sa[i],j)?p-1:p++;
if(p >= n)break;
m = p;//下次基数排序的最大值
}
int k = 0;
n--;
for(i = 0; i <= n; i++)ran[sa[i]] = i;
for(i = 0; i < n; i++){
if(k)k--;
j = sa[ran[i]-1];
while(str[i+k] == str[j+k])k++;
height[ran[i]] = k;
}
}
int ran[MAXN],height[MAXN];
char str[MAXN];
int r[MAXN];
int sa[MAXN];
int nxt[MAXN];
int main(){
int t,cas=1;
scanf("%d",&t);
while(t--){
char X[2];
scanf("%s%s",X,str);
int len = strlen(str);
for(int i = 0; i < len; i++)r[i] = str[i];
r[len] = 0;
da(r,sa,ran,height,len,128);
int pr=-1;
for(int i=len-1;i>=0;i--){
if(X[0]==str[i]) pr=i;
nxt[i]=pr;
}
long long ans=0;
for(int i=1;i<=len;i++){
if(nxt[sa[i]]!=-1)
ans+=len-max(nxt[sa[i]],height[i]+sa[i]);
}
printf("Case #%d: %lld
",cas++,ans);
}
}