zoukankan      html  css  js  c++  java
  • HDU 5769 Substring

    后缀数组。

    然后按照排序完成之后的顺序,每个后缀统计贡献量。

    统计第i个后缀的贡献的时候,如果这个后缀中没有X,贡献度为0。

    有贡献的分3种情况考虑:

    1.如果这个后缀height部分等于0(即与前一个后缀没有公共前缀),那么在height之后的部分中找到第一个X的位置pos,n-pos为贡献度。

    2.如果这个后缀height部分不等于0,如果这个后缀的height部分有X,那么贡献度为n-SA[i]-height[i];

    3.如果这个后缀height部分不等于0,如果这个后缀的height部分没有X,那么需要在height之后的部分中找到第一个X的位置pos,n-pos为贡献度。

    寻找pos的话,可以预处理前缀X个数sum[i],然后二分一下。

    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<set>
    #include<queue>
    #include<stack>
    #include<iostream>
    using namespace std;
    typedef long long LL;
    const double pi=acos(-1.0),eps=1e-8;
    void File()
    {
        freopen("D:\in.txt","r",stdin);
        freopen("D:\out.txt","w",stdout);
    }
    inline int read()
    {
        char c = getchar();  while(!isdigit(c)) c = getchar();
        int x = 0;
        while(isdigit(c)) { x = x * 10 + c - '0'; c = getchar(); }
        return x;
    }
    
    const int maxn=100000+10;
    
    int wa[maxn],wb[maxn],wv[maxn],WS[maxn];
    int cmp(int *r,int a,int b,int l)
    {
        return r[a]==r[b]&&r[a+l]==r[b+l];
    }
    void da(int *r,int *sa,int n,int m)
    {
        int i,j,p,*x=wa,*y=wb,*t;
        for(i=0; i<m; i++) WS[i]=0;
        for(i=0; i<n; i++) WS[x[i]=r[i]]++;
        for(i=1; i<m; i++) WS[i]+=WS[i-1];
        for(i=n-1; i>=0; i--) sa[--WS[x[i]]]=i;
        for(j=1,p=1; p<n; j*=2,m=p)
        {
            for(p=0,i=n-j; i<n; i++) y[p++]=i;
            for(i=0; i<n; i++) if(sa[i]>=j) y[p++]=sa[i]-j;
            for(i=0; i<n; i++) wv[i]=x[y[i]];
            for(i=0; i<m; i++) WS[i]=0;
            for(i=0; i<n; i++) WS[wv[i]]++;
            for(i=1; i<m; i++) WS[i]+=WS[i-1];
            for(i=n-1; i>=0; i--) sa[--WS[wv[i]]]=y[i];
            for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1; i<n; i++)
                x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
        }
        return;
    }
    
    int Rank[maxn],height[maxn];
    void calheight(int *r,int *sa,int n)
    {
        int i,j,k=0;
        for(i=1; i<=n; i++) Rank[sa[i]]=i;
        for(i=0; i<n; height[Rank[i++]]=k)
            for(k?k--:0,j=sa[Rank[i]-1]; r[i+k]==r[j+k]; k++);
        return;
    }
    
    int T,n,a[maxn],SA[maxn],sum[maxn];
    char str[maxn],op[5];
    
    int Find(int D,int l,int r)
    {
        int pos=-1;
        while(l<=r)
        {
            int mid=(l+r)/2;
            if(sum[mid]-D>1) r=mid-1;
            else if(sum[mid]-D==1) pos=mid,r=mid-1;
            else l=mid+1;
        }
        return pos;
    }
    
    int main()
    {
        scanf("%d",&T); int cas=1;
        while(T--)
        {
            scanf("%s%s",op,str); n=strlen(str);
            for(int i=0;i<n;i++) a[i]=(int)str[i];
            a[n]=0; da(a,SA,n+1,300); calheight(a,SA,n);
            memset(sum,0,sizeof sum);
            for(int i=0;i<=n;i++)
            {
                if(i-1>=0) sum[i]=sum[i-1];
                if(a[i]==int(op[0])) sum[i]++;
            }
    
            LL ans=0;
            for(int i=0;i<=n;i++)
            {
                int D; if(SA[i]-1<0) D=0; else D=sum[SA[i]-1];
                if(sum[n]-D==0) continue;
                if(height[i]==0) ans=ans+n-Find(D,SA[i],n);
                else
                {
                    if(sum[SA[i]+height[i]-1]-D!=0) ans=ans+n-SA[i]-height[i];
                    else ans=ans+n-Find(sum[SA[i]+height[i]-1],SA[i]+height[i],n);
                }
            }
            printf("Case #%d: %lld
    ",cas++,ans);
        }
        return 0;
    }
  • 相关阅读:
    CPP标准模板库 随笔
    C++ Concurrency In Action 一些重点
    标准模板库(STL)
    单链表常见操作
    android三大组件之Intent
    数组k平移三种方法(java)
    java中空字符串、null的区别
    java最大最小堆
    java学习笔记之基础知识
    笔试题集锦
  • 原文地址:https://www.cnblogs.com/zufezzt/p/5720983.html
Copyright © 2011-2022 走看看