原题:http://codeforces.com/contest/123/problem/D
题解:题目中定义F(x,y),k 表示y在x中的个数,F(x,y)=k*(k+1)/2。求所有子串的F函数的和。先用后缀数组处理,后缀的前缀表示子串,再用height数组求解。注意到F函数,可以转化成每个y串与后缀匹配的个数,可以用单调栈求解,就是求剩余矩形的面积。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#define pa pair<int,int>
#define x first
#define y second
#define ll long long
#define mp make_pair
using namespace std;
const int N=1e5+10;
char s[N];
int n,rak[N<<1],rak1[N<<1],t[N],tmp[N],cnt[N],sa[N],h[N],v[N];
ll sum,ans;
stack<pa> S;
int main(){
// freopen("cf123d.in","r",stdin);
scanf("%s",s+1);
n=strlen(s+1);
for(int i=1;i<=n;i++) t[s[i]]++;
for(int i=1;i<=1e3;i++) t[i]+=t[i-1];
for(int i=1;i<=n;i++) rak[i]=t[s[i]];
for(int p=1,k=0;k!=n;p<<=1){
memset(cnt,0,sizeof cnt);
for(int i=1;i<=n;i++) cnt[rak[i+p]]++;
for(int i=1;i<=n;i++) cnt[i]+=cnt[i-1];
for(int i=n;i>=1;i--) tmp[cnt[rak[i+p]]--]=i;
memset(cnt,0,sizeof cnt);
for(int i=1;i<=n;i++) cnt[rak[i]]++;
for(int i=1;i<=n;i++) cnt[i]+=cnt[i-1];
for(int i=n;i>=1;i--) sa[cnt[rak[tmp[i]]]--]=tmp[i];
memcpy(rak1,rak,sizeof(rak));
k=1;rak[sa[1]]=1;
for(int i=2;i<=n;i++){
if(rak1[sa[i]]!=rak1[sa[i-1]] || rak1[sa[i]]==rak1[sa[i-1]] && rak1[sa[i]+p]!=rak1[sa[i-1]+p] )k++;
rak[sa[i]]=k;
}
}
for(int i=1,k=0;i<=n;i++){
if(rak[i]==n){
h[rak[i]]=0;continue;
}
if(k) k--;
while(s[i+k]==s[sa[rak[i]+1]+k]) k++;
h[rak[i]]=k;
}
ans=(ll)n*(ll)(n+1)>>1;sum=0;
for(int i=1;i<=n;i++){
pa temp=mp(h[i],1);
while(!S.empty() && S.top().x>h[i]){
sum-=(ll)S.top().x*S.top().y;
temp.y+=S.top().y;
S.pop();
}
sum+=1ll*temp.x*1ll*temp.y;
// printf("%d %d\n",i,sum);
ans+=sum;
S.push(temp);
}
printf("%I64d\n",ans);
return 0;
}