首先学一波字符串的一些性质。首先求出字符串的后缀数组和高度数组之后,就可以求出这个字符串有多少个不同的字串。
PS:这个后缀数组模板为倍增+基数排序。复杂度nlog(n),基数排序O(n),倍增是log但是常数太大,.高度数组可以利用后缀数组O(n)求出!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int MAXN=100010;
int sa[MAXN];
int t1[MAXN],t2[MAXN],c[MAXN];
int Rank[MAXN],lcp[MAXN];
void construct_sa(char s[],int n,int m){
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]=s[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;
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]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+j]==y[sa[i]+j]?p-1:p++;
if(p>=n)break;
m=p;
}
}
void construct_lcp(char s[],int n){
int h=0;lcp[0]=0;
for(int i=0;i<=n;i++) Rank[sa[i]]=i;
for(int i=0;i<n;i++){
if(h>0)h--;
int j=sa[Rank[i]-1];
for(;j+h<n&&i+h<n;h++)
{
if(s[j+h]!=s[i+h])
break;
}
lcp[Rank[i]]=h;
}
}
int fvis[MAXN],pr[MAXN];
char str[MAXN];
int main(){
int T,cas=1;
char ch[10];
scanf("%d",&T);
while(T--){
scanf("%s",ch);
scanf("%s",str);
int n=strlen(str),flag=0,fpr;
memset(fvis,0,sizeof(fvis));
memset(pr,0,sizeof(pr));
for(int i=n-1;i>=0;i--){
if(str[i]==ch[0]){
flag=1;fpr=i;
}
if(flag) fvis[i]=1,pr[i]=fpr;
}
ll ans=0;
construct_sa(str,n+1,128);
construct_lcp(str,n);
for(int i=0;i<=n;i++){
if(fvis[sa[i]]) ans=ans+n-max((sa[i]+lcp[i]),pr[sa[i]]);
}
printf("Case #%d: %I64d\n",cas++,ans);
}
return 0;
}
下面这个是nlog(n)log(n)的模板,做这个题就超时了,利用的是倍增的思想,但是是普通的排序,(nlog(n)).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int MAXN=100010;
int sa[MAXN];
int nn;
int kk;
int Rank[MAXN],lcp[MAXN],tmp[MAXN];
bool compare_sa(int i,int j)
{
if(Rank[i]!=Rank[j])
return Rank[i]<Rank[j];
else
{
int ri=i+kk<=nn?Rank[i+kk]:-1;
int rj=j+kk<=nn?Rank[j+kk]:-1;
return ri<rj;
}
}
void construct_sa(char s[],int n)
{
for(int i=0;i<=n;i++)
{
sa[i]=i;
Rank[i]=i<n?sa[i]:-1;
}
for(kk=1;kk<=n;kk*=2)
sort(sa,sa+n+1,compare_sa);
tmp[sa[0]]=0;
for(int i=1;i<=n;i++)
{
tmp[sa[i]]=tmp[sa[i-1]]+(compare_sa(sa[i-1],sa[i])?1:0);
}
for(int i=0;i<=n;i++)
{
Rank[i]=tmp[i];
}
}
void construct_lcp(char s[],int n){
int h=0;lcp[0]=0;
for(int i=0;i<=n;i++) Rank[sa[i]]=i;
for(int i=0;i<n;i++){
if(h>0)h--;
int j=sa[Rank[i]-1];
for(;j+h<n&&i+h<n;h++)
{
if(s[j+h]!=s[i+h])
break;
}
lcp[Rank[i]]=h;
}
}
int fvis[MAXN],pr[MAXN];
char str[MAXN];
int main(){
int T,cas=1;
char ch[10];
scanf("%d",&T);
while(T--){
scanf("%s",ch);
scanf("%s",str);
int n=strlen(str),flag=0,fpr;
memset(fvis,0,sizeof(fvis));
memset(pr,0,sizeof(pr));
for(int i=n-1;i>=0;i--){
if(str[i]==ch[0]){
flag=1;fpr=i;
}
if(flag) fvis[i]=1,pr[i]=fpr;
}
ll ans=0;
nn=n+1;
construct_sa(str,n+1);
construct_lcp(str,n);
for(int i=0;i<=n;i++){
if(fvis[sa[i]]) ans=ans+n-max((sa[i]+lcp[i]),pr[sa[i]]);
}
printf("Case #%d: %I64d\n",cas++,ans);
}
return 0;
}