[AHOI2013]差异(后缀数组)

首先预处理SA和height数组,由于:

lcp(i,j)=min(height[k])(i+1<=k<=j)

所以问题转化为求每段区间的最小值,

30分算法:$ O(n^2) $ 暴力(简直是对后缀数组的侮辱,人家毕竟O(n*log2(n)的复杂度)

100分算法:整体思路:对于每一个height[i],找出左右边境满足min(h[k])==h[i]。

法一:二分:以为区间最小值是单调不减的,所以可以二分在O(log2(n))复杂度内找出。区间最小值用ST表预处理。

 1 while(l<r)
 2 {
 3         int mid=(l+r)>>1,k=search(mid,i-1);
 4         if(k>=h[i]) r=mid;
 5         else l=mid+1;
 6 }
 7 x=l;
 8 l=i,r=n;
 9 while(l<r)
10 {
11         int mid=(l+r+1)>>1,k=search(i+1,mid);
12         if(k>h[i]) l=mid;
13         else r=mid-1;
14 }
15 y=r;
16 ans-=(y-i+1)*(i-x+1)*h[i]*2;
二分

法二:单调栈:顺序逆序扫一边序列,弹出不满足的并更新其答案,之后把扫到的下标塞进去,最后清空栈中元素把其边境附成1或n

 1         for(int i=1;i<=n;i++)
 2         {
 3                 while(top&&h[stack[top]]>=h[i]) r[stack[top--]]=i-1;
 4                 stack[++top]=i;
 5         }
 6         while(top) r[stack[top--]]=n;
 7         for(int i=n;i>=1;i--)
 8         {
 9                 while(top&&h[stack[top]]>h[i]) l[stack[top--]]=i+1;
10                 stack[++top]=i;
11         }
12         while(top) l[stack[top--]]=1;
单调栈

写在后面:单调栈和ST表真的戳到了我的痛点啊,以前学过了现在思路都忘了,以后学知识还是要领会其灵魂啊!

代码都放了(二分复杂度还是不够优秀,毕竟有个log):

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<algorithm>
  5 #include<queue>
  6 #include<vector>
  7 #include<string>
  8 #include<cstring>
  9 #include<map>
 10 #define int long long
 11 #define max(a,b) (a>b?a:b)
 12 #define m(a) memset(a,0,sizeof(a))
 13 #define AA cout<<"Alita"<<endl
 14 using namespace std;
 15 const int N=5e5+100;
 16 int top,ans,n,m,a[N],X[N],Y[N],c[N],sa[N],rk[N],h[N],st[N][35],stack[N],l[N],r[N];
 17 char s[N];
 18 void init()
 19 {
 20         memset(st,0x3f,sizeof(st));
 21         for(int i=1;i<=n;i++)
 22         {
 23                 st[i][0]=h[i];
 24         }
 25         for(int i=1;i<=n;i++)
 26         {
 27                 for(int j=1;j<=30;j++)
 28                 {
 29                         if((i+(1<<j))-1>n) break;
 30                         st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
 31                 }
 32         }
 33 }
 34 int search(int l,int r)
 35 {
 36         int k=log2(r-l+1);
 37         return min(st[l][k],st[r-(1<<k)+1][k]);
 38 }
 39 void get_sa()
 40 {
 41         m=27;
 42         for(int i=1;i<=m;i++) c[i]=0;
 43         for(int i=1;i<=n;i++) X[i]=a[i];
 44         for(int i=1;i<=n;i++) c[X[i]]++;
 45         for(int i=1;i<=m;i++) c[i]+=c[i-1];
 46         for(int i=n;i>=1;i--) sa[c[X[i]]--]=i;
 47         for(int len=1,p;len<=n;len<<=1)
 48         {
 49                 p=0;
 50                 for(int i=n-len+1;i<=n;i++) Y[++p]=i;
 51                 for(int i=1;i<=n;i++) if(sa[i]>len) Y[++p]=sa[i]-len;
 52                 for(int i=1;i<=m;i++) c[i]=0;
 53                 for(int i=1;i<=n;i++) c[X[Y[i]]]++;
 54                 for(int i=1;i<=m;i++) c[i]+=c[i-1];
 55                 for(int i=n;i>=1;i--) sa[c[X[Y[i]]]--]=Y[i];
 56                 p=1;
 57                 swap(X,Y);
 58                 X[sa[1]]=1;
 59                 for(int i=2;i<=n;i++) 
 60                 {
 61                         X[sa[i]]=Y[sa[i]]==Y[sa[i-1]]&&Y[sa[i]+len]==Y[sa[i-1]+len]?p:++p;
 62                 }
 63                 if(p==n) break;
 64                 m=p;
 65         }
 66         for(int i=1;i<=n;i++) rk[sa[i]]=i;
 67 }
 68 void get_h()
 69 {
 70         for(int i=1,k=0,j;i<=n;i++)
 71         {
 72                 if(k) k--;
 73                 j=sa[rk[i]-1];
 74                 while(a[i+k]==a[j+k]) k++;
 75                 h[rk[i]]=k;
 76         }
 77 }
 78 signed main()
 79 {
 80         //freopen("1.in","r",stdin);
 81         //freopen("1.out","w",stdout);
 82         scanf("%s",s);
 83         n=strlen(s);
 84         for(int i=0;i<n;i++) a[i+1]=s[i]-'a'+1;
 85         get_sa();
 86         get_h();
 87         init();
 88         for(int i=1;i<=n;i++)
 89         {
 90                 while(top&&h[stack[top]]>=h[i]) r[stack[top--]]=i-1;
 91                 stack[++top]=i;
 92         }
 93         while(top) r[stack[top--]]=n;
 94         for(int i=n;i>=1;i--)
 95         {
 96                 while(top&&h[stack[top]]>h[i]) l[stack[top--]]=i+1;
 97                 stack[++top]=i;
 98         }
 99         while(top) l[stack[top--]]=1;
100         for(int i=1;i<=n;i++)
101         {
102                 ans+=(n-i+1)*(n-1)-((r[i]-i+1)*(i-l[i]+1))*h[i]*2;
103         }
104         printf("%lld",ans);
105         return 0;
106 }
单调栈3000ms
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<algorithm>
  5 #include<queue>
  6 #include<vector>
  7 #include<string>
  8 #include<cstring>
  9 #include<map>
 10 #define int long long
 11 #define max(a,b) (a>b?a:b)
 12 #define m(a) memset(a,0,sizeof(a))
 13 #define AA cout<<"Alita"<<endl
 14 using namespace std;
 15 const int N=5e5+100;
 16 int ans,n,m,a[N],X[N],Y[N],c[N],sa[N],rk[N],h[N],st[N][35];
 17 char s[N];
 18 void init()
 19 {
 20         memset(st,0x3f,sizeof(st));
 21         for(int i=1;i<=n;i++)
 22         {
 23                 st[i][0]=h[i];
 24         }
 25         for(int j=1;j<=20;j++)
 26         {
 27                 for(int i=1;i+(1<<(j-1))<=n;i++)
 28                 {
 29                         st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
 30                 }
 31         }
 32 }
 33 int search(int l,int r)
 34 {
 35         int k=log2(r-l+1);
 36         return min(st[l][k],st[r-(1<<k)+1][k]);
 37 }
 38 void get_sa()
 39 {
 40         m=27;
 41         for(int i=1;i<=m;i++) c[i]=0;
 42         for(int i=1;i<=n;i++) X[i]=a[i];
 43         for(int i=1;i<=n;i++) c[X[i]]++;
 44         for(int i=1;i<=m;i++) c[i]+=c[i-1];
 45         for(int i=n;i>=1;i--) sa[c[X[i]]--]=i;
 46         for(int len=1,p;len<=n;len<<=1)
 47         {
 48                 p=0;
 49                 for(int i=n-len+1;i<=n;i++) Y[++p]=i;
 50                 for(int i=1;i<=n;i++) if(sa[i]>len) Y[++p]=sa[i]-len;
 51                 for(int i=1;i<=m;i++) c[i]=0;
 52                 for(int i=1;i<=n;i++) c[X[Y[i]]]++;
 53                 for(int i=1;i<=m;i++) c[i]+=c[i-1];
 54                 for(int i=n;i>=1;i--) sa[c[X[Y[i]]]--]=Y[i];
 55                 p=1;
 56                 swap(X,Y);
 57                 X[sa[1]]=1;
 58                 for(int i=2;i<=n;i++) 
 59                 {
 60                         X[sa[i]]=Y[sa[i]]==Y[sa[i-1]]&&Y[sa[i]+len]==Y[sa[i-1]+len]?p:++p;
 61                 }
 62                 if(p==n) break;
 63                 m=p;
 64         }
 65         for(int i=1;i<=n;i++) rk[sa[i]]=i;
 66 }
 67 void get_h()
 68 {
 69         for(int i=1,k=0,j;i<=n;i++)
 70         {
 71                 if(k) k--;
 72                 j=sa[rk[i]-1];
 73                 while(a[i+k]==a[j+k]) k++;
 74                 h[rk[i]]=k;
 75         }
 76 }
 77 signed main()
 78 {
 79         //freopen("1.in","r",stdin);
 80         //freopen("1.out","w",stdout);
 81         scanf("%s",s);
 82         n=strlen(s);
 83         for(int i=0;i<n;i++) a[i+1]=s[i]-'a'+1;
 84         get_sa();
 85         get_h();
 86         init();
 87         ans=(n+1)*n*(n-1)/2;
 88         for(int i=2,l,r,x,y;i<=n;i++)
 89         {
 90                 if(!h[i]) continue;
 91                 l=2,r=i;
 92                 while(l<r)
 93                 {
 94                         int mid=(l+r)>>1;
 95                         if(search(mid,i-1)>=h[i]) r=mid;
 96                         else l=mid+1;
 97                 }
 98                 x=l;
 99                 l=i,r=n;
100                 while(l<r)
101                 {
102                         int mid=(l+r+1)>>1;
103                         if(search(i+1,mid)>h[i]) l=mid;
104                         else r=mid-1;
105                 }
106                 y=l;
107                 ans-=(i-x+1)*(y-i+1)*h[i]*2;
108         }
109         printf("%lld",ans);
110         return 0;
111 }
二分7000ms
posted @ 2019-08-02 19:38  ATHOSD  阅读(134)  评论(0编辑  收藏  举报