题目链接:点击打开链接
题解:利用后缀数组处理排名,枚举每个位置的后面离它最近的一个X位置和这个位置+height[i]取max(这就可以避免重复),然后用len-这个位置后面还有的数量就行了。
代码:
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
typedef long long ll;
const int mx = 1e5+10;
int root,tot;
char str[mx];
int c[mx],wa[mx],wb[mx],sa[mx],height[mx],ran[mx],pos[mx];
void sort_sa(int m,int n){
int *x=wa,*y=wb,p=0;
for(int i=0;i<m;i++) c[i]=0;
for(int i=0;i<n;i++) c[x[i]=str[i]]++;
for(int i=1;i<m;i++) c[i]+=c[i-1];
for(int i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
for(int k=1;p<n;k<<=1,m=p){
p=0;
for(int i=n-k;i<n;i++) y[p++]=i;//按个位排序
for(int i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
for(int i=0;i<m;i++) c[i]=0;
for(int i=0;i<n;i++) c[x[y[i]]]++;
for(int i=1;i<m;i++) c[i]+=c[i-1];
for(int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
swap(x,y);x[sa[0]] = 0,p = 1;
for(int i=1;i<n;i++)
if(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]) x[sa[i]]=p-1;
else x[sa[i]]=p++;
}
}
void get_height(){
int k=0,len=strlen(str);
for(int i=1;i<=len;i++) ran[sa[i]]=i;
for(int i=0;i<len;i++){
if(k) k--;
int j=sa[ran[i]-1];
while(str[j+k]==str[i+k]) k++;
height[ran[i]]=k;
}
}
int main(){
char temp[10];
int t,cas=1;
scanf("%d",&t);
while(t--){
scanf("%s%s",temp,str);
sort_sa(130,strlen(str)+1);
get_height();
for(int i=strlen(str)-1,p=-1;i>=0;i--){
if(str[i]==temp[0]) p=i;
pos[i]=p;
}
ll ans=0,len=strlen(str);
if(pos[sa[1]] != -1) ans+=len-pos[sa[1]];
for(int i=2;i<=len;i++){
int now = sa[i],p = max(now+height[i],pos[now]);
if(pos[now]==-1) continue;
ans+=len-p;
}
printf("Case #%d: %lld\n",cas++,ans);
}
return 0;
}