3238: [Ahoi2013]差异
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2357 Solved: 1067
[Submit][Status][Discuss]
Description
Input
一行,一个字符串S
Output
一行,一个整数,表示所求值
Sample Input
cacao
Sample Output
54
HINT
2<=N<=500000,S由小写英文字母组成
Source
后缀数组+单调栈
今天终于学了后缀数组 记得去年的寒假 zjw学长给我们讲过这个东西 那时连倍增是什么都不知道。。。
我的后缀数组 是 nlog2n的 (因为我不会那个什么基数排序)
题目是道裸题 可以练练手
代码:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define For(i,x,y) for(int i=x;i<=y;++i) const int N = 500005; using namespace std; char s[N]; int sa[N],rk[N],h[N]; int Log[N];int n; int st[N][20]; struct data{ int i,x,y; bool operator < (const data&a)const{ return (x<a.x||x==a.x&&y<a.y); } bool operator != (const data&a)const{ return (x!=a.x||y!=a.y); } }a[N]; void calh(){ int i,k=0,j; For(i,1,n) rk[sa[i]]=i; for(i=1;i<=n;h[rk[i++]]=k) { if(k>0)k--;int j=sa[rk[i]-1]; while(s[i+k]==s[j+k])k++; } return; } //int lcp(int x,int y){ // if(x==y)return n-x+1; // x=rk[x];y=rk[y]; // if(x>y){x^=y;y^=x;x^=y;} // int len=y-x;x++; // return min(st[x][Log[len]],st[1+y-1<<Log[len]][Log[len]]); //} long long q[N],qsum[N]; int main() { // freopen("sa.in","r",stdin); // freopen("sa.out","w",stdout); scanf("%s",s+1); n=strlen(s+1); For(i,1,n)rk[i]=s[i]; For(i,2,N-1)Log[i]=Log[i>>1]+1; memset(st,127,sizeof(st)); for(int j=0;j<=Log[n]+1;++j){ For(i,1,n) a[i]=(data){i,rk[i],rk[i+(1<<j)]}; sort(a+1,a+n+1);int k=1; For(i,1,n){ rk[a[i].i]=k; if(a[i]!=a[i+1])k++; } } For(i,1,n)sa[rk[i]]=i; calh(); // For(i,1,n)printf("%d ",h[i]); // For(i,1,n)st[i][0]=h[i]; // for(int j=1;j<=Log[n]+1;++j){ // For(i,1,n){ // if(i+(1<<j-1)>n)break; // st[i][j]=min(st[i][j-1],st[i+(1<<j-1)][j-1]); // } // } long long ans=0; int r=0;long long sum=0; For(i,1,n){ long long tsum=1; while(r>0&&q[r]>h[i]) sum=sum-q[r]*qsum[r],tsum+=qsum[r],r--; q[++r]=h[i];qsum[r]=tsum;sum+=tsum*h[i]; ans-=2*sum; } For(i,1,n) ans+=1LL*i*(n-1); cout<<ans; return 0; }