zoukankan      html  css  js  c++  java
  • String and Times

    String and Times

    时间限制: 1 Sec  内存限制: 128 MB

    题目描述

    Now you have a string consists of uppercase letters, two integers A and B. We call a substring wonderful substring when the times it appears in that string is between A and B (A ≤ times ≤ B). Can you calculate the number of wonderful substrings in that string?

    输入

    Input has multiple test cases.
    For each line, there is a string S, two integers A and B.
    ∑Length(S)≤2×10^6,1≤A≤B≤length(S) 

    输出

    For each test case, print the number of the wonderful substrings in a line.

    样例输入

    AAA 2 3
    ABAB 2 2
    

    样例输出

    2
    3

    题意:给定字符串,求出现次数在[l,r]内的不同字符串的个数。
    思路:首先考虑求出现次数大于等于k次的字符串个数。后缀数组的height数组的定义为某个后缀串和它前一个后缀串(此处“前一个”意思是按照字典序的排名来的前一个)的最长公共前缀,那么height数组里若有连续的k-1个数的最小值为min,就代表有一个长度为min的字符串最少出现了k次。
    #include<bits/stdc++.h>
    #define INF LLONG_MAX/2
    #define lson (rt*2)
    #define rson (rt*2+1)
    using namespace std;
    const int N = 2e5+50;
    char s[N];
    
    struct SuffixArray
    {
        int sa[N],rank[N],height[N],cnt[N],a1[N],a2[N],n,m,*x,*y;
        void sort()
        {
            for(int i=0; i<m; i++) cnt[i]=0;
            for(int i=0; i<n; i++) cnt[x[i]]++;
            for(int i=1; i<m; i++) cnt[i]+=cnt[i-1];
            for(int i=n-1; i>=0; i--) sa[--cnt[x[y[i]]]]=y[i];
        }
        void build(char *s,int c_size)
        {
            n=strlen(s);
            m=c_size;
            x=a1;
            y=a2;
            for(int i=0; i<n; i++) x[i]=s[i],y[i]=i;
            x[n]=y[n]=-1;
            sort();
            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;
                sort();
                p=0;
                std::swap(x,y);
                x[sa[0]]=0;
                for(int i=1; i<n; i++)
                {
                    if(y[sa[i]]!=y[sa[i-1]]||y[sa[i]+k]!=y[sa[i-1]+k]) p++;
                    x[sa[i]]=p;
                }
                if(p+1>=n) break;
                m=p+1;
            }
            for(int i=0; i<n; i++) rank[sa[i]]=i;
            height[0]=0;
            int k=0;
            for(int i=0; i<n; i++)
            {
                if(k) k--;
                if(rank[i]==0) continue;
                int j=sa[rank[i]-1];
                while(i+k<n&&j+k<n&&s[i+k]==s[j+k]) k++;
                height[rank[i]]=k;
            }
        }
    } SA;
    
    struct node
    {
        long long val;
        int l,r;
    }tree[N<<2];
    void build(int rt,int l,int r)
    {
        int mid=(l+r)>>1;
        tree[rt].l=l,tree[rt].r=r;
        tree[rt].val=INF;
        if(l==r)
        {
            tree[rt].val=SA.height[l];
            return ;
        }
        build(lson,l,mid);
        build(rson,mid+1,r);
        tree[rt].val=min(tree[lson].val,tree[rson].val);
    }
    int query(int rt,int l,int r)
    {
        int mid=(tree[rt].l+tree[rt].r)/2;
        if(tree[rt].l==l&&tree[rt].r==r)return tree[rt].val;
        if(r<=mid)return query(lson,l,r);
        else
            if(l>mid)return query(rson,l,r);
        else
            return min(query(lson,l,mid),query(rson,mid+1,r));
    }
    
    long long cal(int k,int n)   //求出现k次以上的字符串的个数
    {
        long long ans=0;
        if(k==1)
        {
            for(int i=0;i<n;i++) ans+=(n-SA.sa[i]-SA.height[i]);
            return ans;
        }
        int l=1,r=1+k-2;
        int pre=0;
        while(r<n)//处理全部长度为k-1的连续区间
        {
            int now=query(1,l,r);
            if(now>=pre) ans+=now-pre;//要注意减去上一个区间的贡献
            pre=now;
            l++,r++;
        }
        return ans;
    }
    int main()
    {
        while(scanf("%s",s)!=EOF)
        {
            int L,R;
            scanf("%d%d",&L,&R);
            int ls=strlen(s);
            SA.build(s,255);
            build(1,1,ls-1);
            printf("%lld
    ",cal(L,ls)-cal(R+1,ls));
        }
        return 0;
    }
    View Code
     
  • 相关阅读:
    form表单ajaxSubmit提交并验证
    jQuery幸运大转盘_jQuery+PHP抽奖程序
    thinkphp3.2 + soap
    chart.js图表 传值问题
    window和document的区别理解,bom和dom的区别理解
    JS弹出层制作,以及移动端禁止弹出层下内容滚动,overflow:hidden移动端失效问题
    富文本编辑器summernote的基本使用
    input文件类型上传,或者作为参数拼接的时候注意的问题!
    使用input选择本地图片,并且实现预览功能
    整体页面加载和某一模块加载监听
  • 原文地址:https://www.cnblogs.com/tian-luo/p/11296239.html
Copyright © 2011-2022 走看看