• luogu P1117 [NOI2016]优秀的拆分


    传送门

    这题居然暴力有95,,,

    先考虑暴力,(AABB)显然可以看成两个相邻的(AA),记(a_i)为以i为结尾的(AA)个数,(b_i)为以i为结尾的(AA)个数,可以直接哈希统计每一种,答案为(sum_{i=1}^{n-1}a_ib_{i+1})

    然后考虑优化统计答案,首先枚举一种长度(lin[1,lfloorfrac{n}{2} floor]),然后每l位置放一个关键点,显然长度为(2l)(AA)串会覆盖两个关键点,并且两个点在(AA)中的(A)出现位置相同

    显然(AA)要满足(min(lcs(i,j),l)+min(lcp(i,j),l)>l),我们可以考虑利用这个条件,记(l1=min(lcs(i,j),l),l2=min(lcp(i,j),l)),那么可以知道(s[i-l1+1,i+l2-1]=s[j-l1+1,j+l2-1]),从而可以知道,在(s[i-l1+1,i+l2-1])中任取长度为(l)的子串,这个子串后面一定接着一个一样的串,所以可以统计出左端点在([i-l1+1,i+l2-l]),长度为(2l)(AA)串,所以a数组区间([i-l1+l+l+1,i+l2+l])+1,b数组区间([i-l1+1,i+l2-l])+1,差分统计即可

    复杂度(sum_{i=1}^{frac{n}{2}}frac{n}{i}),大约是(nlogn)

    #include<bits/stdc++.h>
    #define LL long long
    #define il inline
    #define re register
    
    using namespace std;
    const int N=4e4+10;
    il LL rd()
    {
        LL x=0,w=1;char ch=0;
        while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
        return x*w;
    }
    int sa[N],rr[N],rk[N],wx[N],wr[N],bk[N],he[N];
    int mip[N][15],mis[N][15];
    char cc[N];
    int n,lz,aa[N],bb[N];
    il void gSA(bool o)
    {
        memset(wr,0,sizeof(wr));
        int sz=128;
        for(int i=0;i<=sz;++i) bk[i]=0;
        for(int i=1;i<=n;++i) ++bk[rk[i]=cc[i]];
        for(int i=1;i<=sz;++i) bk[i]+=bk[i-1];
        for(int i=n;i;--i) sa[bk[rk[i]]--]=i;
        int j=1,tp=0,p=0;
        while(p<n)
        {
            tp=0;
            for(int i=n-j+1;i<=n;++i) wx[++tp]=i;
            for(int i=1;i<=n;++i) if(sa[i]>j) wx[++tp]=sa[i]-j;
            for(int i=1;i<=n;++i) wr[i]=rk[wx[i]];
            for(int i=0;i<=sz;++i) bk[i]=0;
            for(int i=1;i<=n;++i) ++bk[wr[i]];
            for(int i=1;i<=sz;++i) bk[i]+=bk[i-1];
            for(int i=n;i;--i) sa[bk[wr[i]]--]=wx[i];
            for(int i=1;i<=n;++i) wr[i]=rk[i];
            rk[sa[1]]=p=1;
            for(int i=2;i<=n;++i) rk[sa[i]]=p+=(wr[sa[i]]==wr[sa[i-1]]&&wr[sa[i]+j]==wr[sa[i-1]+j])^1;
            sz=p,j<<=1;
        }
        for(int i=1;i<=n;++i) he[i]=0;
        for(int i=1;i<=n;++i)
        {
            if(he[rk[i-1]]) he[rk[i]]=he[rk[i-1]]-1;
            int j=sa[rk[i]-1];
            while(cc[i+he[rk[i]]]==cc[j+he[rk[i]]]) ++he[rk[i]];
        }
        int mi[N][15];
        memset(mi,0,sizeof(mi));
        for(int i=1;i<=n;++i) mi[i][0]=he[i];
        for(int j=1;j<=lz;++j)
        {
            for(int i=1;i<=n;++i)
                mi[i][j]=min(mi[i][j-1],mi[i+(1<<(j-1))][j-1]);
        }
        o?memcpy(mip,mi,sizeof(mi)):memcpy(mis,mi,sizeof(mi));
    }
    il int lcp(int i,int j)
    {
        i=rr[i],j=rr[j];
        if(i==j) return -n;
        if(i>j) swap(i,j);
        ++i;
        int l=log2(j-i+1);
        return min(mip[i][l],mip[j-(1<<l)+1][l]);
    }
    il int lcs(int i,int j)
    {
        i=rk[n-i+1],j=rk[n-j+1];
        if(i==j) return -n;
        if(i>j) swap(i,j);
        ++i;
        int l=log2(j-i+1);
        return min(mis[i][l],mis[j-(1<<l)+1][l]);
    }
    
    int main()
    {
        int T=rd();
        while(T--)
        {
            memset(aa,0,sizeof(aa));
            memset(bb,0,sizeof(bb));
            scanf("%s",cc+1);
            n=strlen(cc+1),lz=log2(n);
            gSA(1);
            memcpy(rr,rk,sizeof(rk));
            for(int i=1;i<=n/2;++i) swap(cc[i],cc[n-i+1]);
            gSA(0);
            for(int l=1;l<=n/2;++l)
                for(int i=1,j=l+1;j<=n;i+=l,j+=l)
                {
                    int l1=min(lcs(i,j),l),l2=min(lcp(i,j),l);
                    if(l1+l2>l)
                    {
                        ++aa[i-l1+1+l+l-1],--aa[i+l2+l];
                        ++bb[i-l1+1],--bb[i+l2-l+1];
                    }
                }
            for(int i=1;i<=n;++i) aa[i]+=aa[i-1],bb[i]+=bb[i-1];
            LL ans=0;
            for(int i=1;i<n;++i) ans+=1ll*aa[i]*bb[i+1];
            printf("%lld
    ",ans);
        }
        return 0;
    }
    

    沙雕(nlog^2n)做法

  • 相关阅读:
    原生searchView 自定义样式
    面试问题总结
    Android Studio开发环境搭建
    JAVA基本程序设计结构
    JAVA大数使用
    sql
    普通树的递归遍历
    6_43_递归交换二叉树中所有节点的左右子树
    6_42_二叉树递归求叶子节点个数
    6_44_二叉树中值为x的节点为根的子树的深度
  • 原文地址:https://www.cnblogs.com/smyjr/p/10398349.html
Copyright © 2020-2023  润新知