[BZOJ4650][NOI2016]优秀的拆分(hash/后缀数组+RMQ)

题目:

我是超链接

题解:

95分的hash(为什么暴力分这么良心啊)
显然我们不需要找AABB的形式,只需要找到AA的形式就好了
l[i]表示i位及前面的有多少AA的形式,r[i]表示i+1位及以后有多少AA的形式
那么答案就是 l [ i ] r [ i ]
95就行了我hin满意了
感觉也是后缀家族的一员吧,讲解的话这个blog讲的特别好啊,后缀数组+RMQ也很常见,当个板子练练吧
最后用了一个差分,因为是区间加操作,用差分比较好,时间复杂度为O(n/1+n/2+…+n/n)=O(nlogn)

代码:

95的hash

#include <cstdio>
#include <cstring>
#define LL long long 
using namespace std;
const int base=131;
const int mod=998244353;
const int N=2005;
LL mul[N],hash[N];char st[N];
int main()
{
    int T;scanf("%d",&T);
    mul[0]=1;
    for (int i=1;i<=2000;i++) mul[i]=mul[i-1]*base%mod;
    while (T--)
    {
        scanf("%s",st+1);int n=strlen(st+1);
        for (int i=1;i<=n;i++)
          hash[i]=(hash[i-1]*base+st[i])%mod;
        int ans=0;
        for (int i=1;i<=n;i++) 
        {
            int l=0,r=0;
            for (int j=1;j<=n;j++)
            {
                if (i-j*2>=0) 
                  if ((hash[i]-hash[i-j]*mul[j]%mod+mod)%mod==(hash[i-j]-hash[i-j*2]*mul[j]%mod+mod)%mod) l++;
                if (i+j*2<=n) 
                  if ((hash[i+j]-hash[i]*mul[j]%mod+mod)%mod==(hash[i+2*j]-hash[i+j]*mul[j]%mod+mod)%mod) r++;
            }
            ans+=l*r;
        }
        printf("%d\n",ans);
    }
}                        

100

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#define LL long long
using namespace std;
const int N=60005;
int n;LL l[N],r[N];char st[N];
struct hzsz
{
    int sa[N],x[N],y[N],f[N][25],rak[N],height[N],c[N];
    char s[N];
    void build_sa()
    {
        int m=300;
        for (int i=0;i<m;i++) c[i]=0;
        for (int i=0;i<n;i++) c[x[i]=s[i]]++;
        for (int i=1;i<m;i++) c[i]+=c[i-1];
        for (int i=n-1;i>=0;i--) sa[--c[x[i]]]=i;

        for (int k=1;k<=n;k<<=1)
        {
            int p=0;
            for (int i=n-k;i<n;i++) y[p++]=i;
            for (int i=0;i<n;i++) if (sa[i]>=k) y[p++]=sa[i]-k;

            for (int i=0;i<m;i++) c[i]=0;
            for (int i=0;i<n;i++) c[x[y[i]]]++;
            for (int i=1;i<m;i++) c[i]+=c[i-1];
            for (int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];

            swap(x,y); p=1; x[sa[0]]=0;
            for (int i=1;i<n;i++) x[sa[i]]= y[sa[i]]==y[sa[i-1]] 
            && ((sa[i]+k>=n?-1:y[sa[i]+k])==(sa[i-1]+k>=n?-1:y[sa[i-1]+k]))?p-1:p++;
            if (p>n) break;
            m=p; 
        }
    }
    void build_height()
    {
        for (int i=0;i<n;i++) rak[sa[i]]=i;
        height[0]=0;int k=0;
        for (int i=0;i<n;i++)
        {
            if (!rak[i]) continue;
            if (k) k--;
            int j=sa[rak[i]-1];
            while (i+k<n && j+k<n && s[i+k]==s[j+k]) k++;
            height[rak[i]]=k;
        }
    }
    void init()
    {
        memset(sa,0,sizeof(sa));
        memset(f,0,sizeof(f));
        memset(x,0,sizeof(x));
        memset(y,0,sizeof(y));
        memset(height,0,sizeof(height));
        memset(rak,0,sizeof(rak));
        build_sa();build_height();
        for (int i=0;i<n;i++) f[i][0]=height[i];
        for (int i=1;i<20;i++)
          for (int j=0;j<n;j++)
            if (j+(1<<i)-1<n) f[j][i]=min(f[j][i-1],f[j+(1<<(i-1))][i-1]);
            else break;
    }
    int lcp(int a,int b)
    {
        int l=rak[a],r=rak[b]; 
        if (r<l) swap(l,r);
        if (r<0) return 0;l++;
        int k=log2(r-l+1);
        return min(f[l][k],f[r-(1<<k)+1][k]);
    }
}s1,s2;
int main()
{
    int T;scanf("%d",&T);
    while (T--)
    {
        memset(l,0,sizeof(l));memset(r,0,sizeof(r));
        scanf("%s",st);n=strlen(st);
        for (int i=0;i<n;i++) s1.s[i]=st[i],s2.s[i]=st[n-i-1];
        s1.init(); s2.init();
        for (int i=1;i<=n/2;i++)
        {
            int last=0;
            for (int j=1;j+i<=n;j+=i)
            {
                int x=s1.lcp(j-1,j+i-1),y=s2.lcp(n-j-i,n-j);
                int ll=max(j,j+i-y),rr=min(j+i,j+x)-1;
                if (ll<=rr)
                {
                    l[ll+i]++; l[rr+i+1]--;
                    r[ll-i]++; r[rr-i+1]--;
                }
            }
        }
        LL ans=0;
        for (int i=1;i<=n;i++) l[i]+=l[i-1],r[i]+=r[i-1];
        for (int i=1;i<=n;i++) ans+=l[i]*r[i];
        printf("%lld\n",ans);
    }
}

猜你喜欢

转载自blog.csdn.net/blue_cuso4/article/details/80456998
今日推荐