• 2534: Uva10829L-gap字符串


    2534: Uva10829L-gap字符串

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 177  Solved: 66
    [Submit][Status][Discuss]

    Description

    有一种形如uvu形式的字符串,其中u是非空字符串,且V的长度正好为L,那么称这个字符串为L-Gap字符串 
    给出一个字符串S,以及一个正整数L,问S中有多少个L-Gap子串. 

    Input

    第一行一个数字L 
    第二行一个字符串S 

     

    Output

    一个数字表示S中有多少个L-Gap子串. 

     

    Sample Input

    3
    aabbaa



    Sample Output

    2

    Hint
    S的长度不超过50000,L<=10

    HINT

     

    Source

    【题意】

      UVU形式的串的个数,V的长度规定,U要一样,位置不一样即为不同字串

    【分析】

      表示做了poj3693还是不会做这题。

      为什么会想到枚举L然后分块呢????

      为什么呢????

      这种方法于我而言还是有点难理解的啊。

      主要是分块!!

      

    任意一个满足条件的UVU,假设U的长度是len,那么左端的U必然包含按照len切分的T串的某个字串,及0,len,2len,3len...。(这点要仔细想清楚)

    那么枚举每个端点i*len,然后利用RMQ求后缀i*len和后缀i*len+L+len的LCP,然后字符串T反向,再求一遍反向的LCP2。(其中LCP要小于等于len,否则会重复,仔细想清楚)

    最后累加求和sum+=(LCP+LCP2-1)-len+1。(这点想清楚为什么是-len)

    blog:http://blog.csdn.net/u011526463/article/details/14000693

      

      还有,其实,貌似不用后缀数组直接两个while前后就可以了。时间貌似还是nlogn的。

    这道题我看了100遍!!

    现在又明白了一点了ORZ。。。分块屌ORZ。。。

    好吧,是按照u的长度分块!!

    为什么呢,目的是:答案串的u至少包含一个分割点(上面的蓝色突起)

    我们对于其包含的第一个分割点时计算他!!!(就是上面红色圈起的部分)

    如果匹配长度越过第二个分割点,那么是会重复计算的,所以在这一题,向前匹配和向后匹配都可以直接while,越过分割点的时候就结束。

    ORZ。。。                                                                                                                       (转载自Konjakmoyu)

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=5e5+10;
    typedef long long ll;
    int n,T,L,cas,c[N],h[N],sa[N],tsa[N],rank[N],trank[N];
    int log2[N],f[N][20];
    char s[N];
    void DA(int maxx=256){
        int p;
        for(int i=0;i<=maxx;i++) c[i]=0;
        for(int i=1;i<=n;i++) c[rank[i]=s[i]]++;
        for(int i=2;i<=maxx;i++) c[i]+=c[i-1];
        for(int i=n;i;i--) sa[c[rank[i]]--]=i;
        trank[sa[1]]=p=1;
        for(int i=2;i<=n;i++){
            if(rank[sa[i]]!=rank[sa[i-1]]) p++;
            trank[sa[i]]=p;
        }
        for(int i=1;i<=n;i++) rank[i]=trank[i];
        for(int k=1;p<n;k<<=1,maxx=p){
            p=0;
            for(int i=n-k+1;i<=n;i++) tsa[++p]=i;
            for(int i=1;i<=n;i++) if(sa[i]>k) tsa[++p]=sa[i]-k;
            for(int i=0;i<=maxx;i++) c[i]=0;
            for(int i=1;i<=n;i++) trank[i]=rank[tsa[i]];
            for(int i=1;i<=n;i++) c[trank[i]]++;
            for(int i=2;i<=maxx;i++) c[i]+=c[i-1];
            for(int i=n;i;i--) sa[c[trank[i]]--]=tsa[i];
            trank[sa[1]]=p=1;
            for(int i=2;i<=n;i++){
                if(rank[sa[i]]!=rank[sa[i-1]]||rank[sa[i]+k]!=rank[sa[i-1]+k]) p++;
                trank[sa[i]]=p;
            }
            for(int i=1;i<=n;i++) rank[i]=trank[i];
        }
        for(int i=1,k=0;i<=n;i++){
            int j=sa[rank[i]-1];
            while(s[i+k]==s[j+k]) k++;
            h[rank[i]]=k;if(k>0) k--;
        }
    }
    void RMQ(){
        for(int i=1;i<=n;i++) f[i][0]=h[i];
        for(int i=2;i<=n;i++) log2[i]=log2[i>>1]+1;
        for(int j=1;j<=log2[n];j++){
            for(int i=1;i+(1<<j)-1<=n;i++){
                f[i][j]=min(f[i][j-1],f[i+(1<<j-1)][j-1]);
            }
        }
    }
    int query(int l,int r){
        int a=rank[l],b=rank[r];
        if(a>b) swap(a,b);
        a++;
        int k=log2[b-a+1];
        return min(f[a][k],f[b-(1<<k)+1][k]);
    }
    int main(){
        scanf("%d%s",&L,s+1);n=strlen(s+1);
        DA();RMQ(); 
        ll ans=0;
        for(int len=1,now,x,y,z;len<=n;len++){
            for(int i=0;i<=n/len;i++){
                now=len*i+1;y=0;
                if(s[now]!=s[now+L+len]||now+L+len>n) continue;
                x=min(len,query(now,now+L+len));
                while(s[now-y-1]==s[now+L+len-y-1]&&y+1<len) y++;
                if(x+y-len+1>0) ans+=(ll)(x+y-len+1);
            }
        }
        printf("%lld
    ",ans);
        return 0;
    }

    ps:UVA上rank是关键字。(然后不用std空间就好了或改一下变量名)

    代码:UVA - 10829 

  • 相关阅读:
    NPAPI插件开发记录(一) .rc文件 支持Chrome和FireFox
    C语言实现数组快速排序(含对算法的详细解释)
    VBA Address expression
    一起学习winphone7开发系列课程 by 李振
    Performance and memory profiler JefBrains dotTrace tool
    WPF自学教程系列2:如何在xaml文件添加引用?
    for foreach 效率比较
    20130131. CLR C++
    C++ XML编程
    c++ 内存泄露检测
  • 原文地址:https://www.cnblogs.com/shenben/p/6595853.html
Copyright © 2020-2023  润新知