bzoj 4650: [Noi2016]优秀的拆分

Posted Achen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 4650: [Noi2016]优秀的拆分相关的知识,希望对你有一定的参考价值。

传送门

随便后缀数组跑一跑n^2就有95分,简直不能再划算啊。

正解如图。然后差分就好了。

灵魂画手。

这两天bug奇多,难得1A,老泪纵横。

 

//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<ctime>
const int N=100007;
typedef long long LL;
using namespace std;
int T,n,sa1[N],sa2[N],h1[N][20],h2[N][20],rak1[N],rak2[N],cl[N],cr[N],cc1[N],cc2[N];
char s[N];

template<typename T> void read(T &x) {
    T f=1; x=0; char ch=getchar();
    while(ch!=\'-\'&&(ch<\'0\'||ch>\'9\')) ch=getchar();
    if(ch==\'-\') f=-1,ch=getchar();
    for(;ch>=\'0\'&&ch<=\'9\';ch=getchar()) x=x*10+ch-\'0\'; x*=f;
}

int cmp(int a,int b,int k,int y[]) {
    int o1=a+k>=n?-1:y[a+k];
    int o2=b+k>=n?-1:y[b+k];
    return (o1==o2)&&(y[a]==y[b]); 
}

void make_hight(int sa[],int h[][20],int rank[]) {
    for(int i=0;i<n;i++) rank[sa[i]]=i;
    for(int i=0,k=0;i<n;i++) {
        if(!rank[i]) continue;
        if(k) k--;
        int j=sa[rank[i]-1];
        while(s[i+k]==s[j+k]) k++;
        h[rank[i]-1][0]=k;
    }
    for(int j=1;j<20;j++)     
        for(int i=0;i+(1<<j-1)<n;i++) 
            h[i][j]=min(h[i][j-1],h[i+(1<<j-1)][j-1]);
}

void make_sa(int sa[],int h[][20],int rank[]) {
    static int t1[N],t2[N],c[N];
    int *x=t1,*y=t2,i,k,m=\'z\'+1;
    for(i=0;i<m;i++) c[i]=0;
    for(i=0;i<n;i++) c[x[i]=s[i]]++;
    for(i=1;i<m;i++) c[i]+=c[i-1];
    for(i=0;i<n;i++) sa[--c[x[i]]]=i;
    for(k=1;k<=n;k<<=1) {
        int p=0;
        for(i=n-k;i<n;i++) y[p++]=i;
        for(i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k; 
        for(i=0;i<m;i++) c[i]=0;
        for(i=0;i<n;i++) c[x[y[i]]]++;
        for(i=1;i<m;i++) c[i]+=c[i-1];
        for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
        swap(x,y); p=1; x[sa[0]]=0;
        for(i=1;i<n;i++) 
            x[sa[i]]=cmp(sa[i-1],sa[i],k,y)?p-1:p++;
        if(p>=n) break;
        m=p;
    }
    make_hight(sa,h,rank);
}

int get_lcp(int l,int r,int h[][20],int rank[]) {
    l=rank[l]; r=rank[r]; if(l>r) swap(l,r);
    int k=0;
    while(l+(1<<k)<=r) k++; k--;
    return min(h[l][k],h[r-(1<<k)][k]);
} 

void clear() {
    memset(cc1,0,sizeof(cc1));
    memset(cc2,0,sizeof(cc2));
}

int main() {
    read(T);
    while(T--) {
        scanf("%s",s);
        n=strlen(s);
        make_sa(sa1,h1,rak1);
        for(int i=0;i<n/2;i++) swap(s[i],s[n-i-1]);
        make_sa(sa2,h2,rak2);
        for(int l=1;l<=n/2;l++) 
            for(int i=l;i<n;i+=l) {
                int j=i+l;
                int x=j>=n?0:min(l-1,get_lcp(i,j,h1,rak1)); 
                int y=j-1>=n?0:min(l,get_lcp(n-i,n-j,h2,rak2));
                if(x+y<l) continue;
                cc1[i-y]+=1; cc1[i+x-l+1]-=1;
                cc2[i-y+2*l-1]+=1; cc2[i+x-l+1+2*l-1]-=1;
            }
        int sum1=0,sum2=0; 
        for(int i=0;i<n;i++) {
            sum1+=cc1[i]; sum2+=cc2[i];
            cl[i]=sum1; cr[i]=sum2; 
        }
        LL ans=0;
        for(int i=0;i+1<n;i++) 
            ans+=(LL)cr[i]*cl[i+1];
        printf("%lld\\n",ans);
        if(T) clear();
    } 
    return 0;
}
/*
1
aabaabaabaa
*/
View Code

 

以上是关于bzoj 4650: [Noi2016]优秀的拆分的主要内容,如果未能解决你的问题,请参考以下文章

UOJ#219/BZOJ4650 [NOI2016]优秀的拆分 SA ST表

BZOJ 4650 [Noi2016]优秀的拆分:后缀数组

[bzoj4650][Noi2016]优秀的拆分——后缀数组

BZOJ 4650 [Noi2016]优秀的拆分

bzoj4650: [Noi2016]优秀的拆分

BZOJ4650&UOJ219优秀的拆分(二分,hash)