1. 程式人生 > >bzoj3238: [Ahoi2013]差異

bzoj3238: [Ahoi2013]差異

line printf mil height ems -i 後綴數組 暴力 color

發現我做題都是一眼秒算法,然後就不知道怎麽做了。

好的這次一眼就是後綴數組了。

然後這個式子前面的可以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\n",(len-1)*(1+len)*len/2-2*solve(len)); return 0; }

bzoj3238: [Ahoi2013]差異