发现我做题都是一眼秒算法,然后就不知道怎么做了。
好的这次一眼就是后缀数组了。
然后这个式子前面的可以O(1)公式搞定,其实问的就是sigema(LCP(Ti,Tj))
然后先写了个暴力,就大概长这样:
int pos[510000],f[510000],ff[510000]; int solve(int n) { int ans=0; memset(f,0,sizeof(f)); for(int i=1;i<n;i++) { if(f[i]!=0)f[i]=f[pos[i]]-ff[i]; else { int mi=2147483647; for(int j=i+1;j<=n;j++) { if(height[j]<=mi) { mi=height[j]; if(j-1!=i) { pos[j-1]=i; ff[i]=f[i]; } } f[i]+=mi; } } ans+=f[i]; } return ans; }
可以发现mi是递减的嘛,然后对于一个height值,它所能影响的区间就是前一个比他大值的位置+1 ~ 后一个比他大的位置-1,然后就是两个单调栈搞一搞了。
有个有趣的问题,就是假如相邻的值相等,那么答案就会多算,所以要变成<=
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; int a[510000],tt[510000]; int sa1[510000],sa2[510000],Rank[510000]; int Rsort[510000]; void get_sa(LL n,int m) { for(int i=1;i<=n;i++)Rank[i]=a[i]; memset(Rsort,0,sizeof(Rsort)); for(int i=1;i<=n;i++)Rsort[Rank[i]]++; for(int i=1;i<=m;i++)Rsort[i]+=Rsort[i-1]; for(int i=n;i>=1;i--)sa1[Rsort[Rank[i]]--]=i; int ln=1,p=0; while(p<n) { int k=0;for(int i=n-ln+1;i<=n;i++)sa2[++k]=i; for(int i=1;i<=n;i++) if(sa1[i]-ln>0)sa2[++k]=sa1[i]-ln; memset(Rsort,0,sizeof(Rsort)); for(int i=1;i<=n;i++)Rsort[Rank[sa2[i]]]++; for(int i=1;i<=m;i++)Rsort[i]+=Rsort[i-1]; for(int i=n;i>=1;i--)sa1[Rsort[Rank[sa2[i]]]--]=sa2[i]; for(int i=1;i<=n;i++)tt[i]=Rank[i]; p=1;Rank[sa1[1]]=1; for(int i=2;i<=n;i++) { if(tt[sa1[i-1]]!=tt[sa1[i]]||tt[sa1[i-1]+ln]!=tt[sa1[i]+ln])p++; Rank[sa1[i]]=p; } ln*=2;m=p; } } LL height[510000]; void get_he(int n) { int j;LL h=0; for(int i=1;i<=n;i++) { j=sa1[Rank[i]-1]; if(h!=0)h--; while(a[i+h]==a[j+h])h++; height[Rank[i]]=h; } } //--------------sa------------- int top,sta[510000]; LL l[510000],r[510000]; LL solve(LL n) { top=0; for(int i=1;i<=n;i++) { while(top>0&&height[i]<height[sta[top]]) r[sta[top]]=i-1, top--; sta[++top]=i; } while(top>0) r[sta[top]]=n, top--; for(int i=n;i>=1;i--) { while(top>0&&height[i]<=height[sta[top]]) l[sta[top]]=i+1, top--; sta[++top]=i; } while(top>0) l[sta[top]]=1, top--; LL ans=0; for(int i=1;i<=n;i++) ans+=(i-l[i]+1)*(r[i]-i+1)*height[i]; return ans; } char ss[510000]; int main() { scanf("%s",ss+1);LL len=strlen(ss+1); for(int i=1;i<=len;i++)a[i]=ss[i]-'a'+1; get_sa(len,200);get_he(len); printf("%lld ",(len-1)*(1+len)*len/2-2*solve(len)); return 0; }