• 阿狸的打字机


    1946 阿狸的打字机

     

    2011年NOI全国竞赛

     时间限制: 1 s
     空间限制: 256000 KB
     题目等级 : 大师 Master
     
     
    题目描述 Description

    阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机。打字机 上只有 28 个按键,分别印有 26 个小写英文字母和'B'、'P'两个字母。 经阿狸研究发现,这个打字机是这样工作的:

     输入小写字母,打字机的一个凹槽中会加入这个字母(按 P 前凹槽中至 少有一个字母)。

     按一下印有'B'的按键,打字机凹槽中最后一个字母会消失。

     按一下印有'P'的按键,打字机会在纸上打印出凹槽中现有的所有字母并 换行,但凹槽中的字母不会消失(保证凹槽中至少有一个字母)。

    例如,阿狸输入 aPaPBbP,纸上被打印的字符如下: a aa ab 我们把纸上打印出来的字符串从 1 开始顺序编号,一直到 n。打字机有一个 非常有趣的功能,在打字机中暗藏一个带数字的小键盘,在小键盘上输入两个数 (x,y)(其中 1≤x,y≤n),打字机会显示第 x 个打印的字符串在第 y 个打印的字符串 中出现了多少次。 阿狸发现了这个功能以后很兴奋,他想写个程序完成同样的功能,你能帮助 他么?

    输入描述 Input Description

    输入的第一行包含一个字符串,按阿狸的输入顺序给出所有阿狸输入的字符。 第二行包含一个整数 m,表示询问个数。 接下来 m 行描述所有由小键盘输入的询问。其中第 i 行包含两个整数 x, y, 表示第 i 个询问为(x, y)。

    输出描述 Output Description

    输出 m 行,其中第 i 行包含一个整数,表示第 i 个询问的答案。 

    样例输入 Sample Input

    aPaPBbP

    3

    1 2

    1 3

    2 3

    样例输出 Sample Output

    2

    1

    数据范围及提示 Data Size & Hint

    1≤n≤ 105,1≤m≤ 105

    ——————————————————————————————————————————————————————————————————————

    N长时间没有更新了,抄了一个!!

    AC自动机fail树+DFS序+树状数组

     求一个字符串A在另一个字符串B中出现的次数。

    首先建立各个串的AC自动机。沿着B串每一个前缀的fail指针走,如果可以走到A串,那么A就是B串的当前前缀的后缀。统计个数就可以了。

    但是上面的方法太慢。

    可以这样想:既然沿失败指针可以走到A,那么把失败指针反向,再沿着失败指针走可以走到的B串中的点的个数就是答案。

    如何统计走到的点中有多少是B串的呢?DFS序+树状数组

    因为是字符单个增加,所以当完成B串,B串中的每一个节点对应的位置记为1,则A串末位节点的子树节点的和就是答案。

    作出DFS序,用树状数组维护就好了。

    确实有点难,看懂了想法还是出了点小问题:树状数组维护的长度应当用dfs序的个数。我的使用的总长度,结果三个点超时。

    ——————————————————————————————————————————————————————————————————————

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxn 100005
    using namespace std;
    char s[maxn];
    int sz[maxn<<1];
    int m;
    void readint(int &x)
    {
        char c=getchar();
        for(;c<'0'|| c>'9';c=getchar());
        x=0;
        for(;c>='0' &&c<='9';c=getchar())x=x*10+c-'0';
    }
    inline void add(int p,int x)
    {
        for(;p<=l;p+=p&-p)sz[p]+=x;
     } 
    inline int cha(int p)
     {
         int sum=0;
         for(;p>0;p-=p&-p)sum+=sz[p];
         return sum;
     }
    int ftu[maxn],ftv[maxn],next[maxn];
    int ftjs=0,fth[maxn];
    inline void addf(int u,int v)
    {
        ftu[++ftjs]=u;ftv[ftjs]=v;
        next[ftjs]=fth[u];fth[u]=ftjs;
    }
    struct ASK
    { 
        int u,v,id;
        inline bool operator < (const ASK a)const 
        {
            return v<a.v;
        }
    }ask[maxn];
    int ans[maxn];
    int l[maxn],r[maxn],dfsx=0;
    struct AC
    {
        int ch[maxn][26],fa[maxn],f[maxn],tot,js,now,cnt,ps[maxn],q[maxn],tail,head;
        void build()
        {
            cnt=now=0,tot=strlen(s);
            memset(ch[0],0,sizeof(ch[0]));
            for(int i=0;i<tot;i++)
            if(s[i]=='P')
            {
                ps[++js]=now;    
            }
            else if(s[i]=='B') now=fa[now];
            else
            {
                int tp=s[i]-'a';
                if(!ch[now][tp])
                {
                    memset(ch[++cnt],0,sizeof(ch[cnt]));
                    ch[now][tp]=cnt;fa[cnt]=now;
                }
                now=ch[now][tp];
            }
        }
        void bf()
        {
            head=tail=0;
            for(int i=0;i<26;i++)
                if(ch[0][i])q[++tail]=ch[0][i];
            while(tail>head)
            {
                int son,cur=q[++head];
                for(int i=0;i<26;i++)
                    if(son=ch[cur][i])
                    {
                        f[son]=ch[f[cur]][i];q[++tail]=son;
                    }
                    else ch[cur][i]=ch[f[cur]][i];
            }
        }
        void work()
        {
            int jss=0,k=1;
            now=0;
            for(int i=0;i<tot;i++)
                if(s[i]=='P')
                {
                    for(jss++;ask[k].v==jss && k<=m;k++)    //jss第几个结束点 
                    {
                        int pp=ps[ask[k].u];
                        ans[ask[k].id]= cha(r[pp])-cha(l[pp]-1);
                    }
                }
                else if(s[i]=='B')
                {
                    add(l[now],-1);
                    now=fa[now];
                }
                else 
                {
                    now=ch[now][s[i]-'a'];
                    add(l[now],1);
                }
        }
    }ac;
    
    inline void dfs(int u)
    {
        l[u]=++dfsx;
        for(int i=fth[u];i;i=next[i])
            dfs(ftv[i]);
        r[u]=++dfsx;
    }
    int main()
    {
        scanf("%s",s);
        ac.build();ac.bf();
        for(int i=1;i<=ac.cnt;i++)addf(ac.f[i],i);
        dfs(0);
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            readint(ask[i].u);readint(ask[i].v);
            ask[i].id=i;    //u,v为第几条字符串 
        }
        sort(ask+1,ask+m+1);
        ac.work();
        for(int i=1;i<=m;i++)printf("%d
    ",ans[i]);
        
        return 0;
    }
  • 相关阅读:
    RDIFramework.NET框架基于Quartz.Net实现任务调度详解及效果展示
    Quartz.Net实现作业定时调度详解
    微信公众号开发系列-13、基于RDIFramework.NET框架整合微信开发应用效果展示
    微信公众号开发C#系列-12、微信前端开发利器:WeUI
    微信公众号开发C#系列-11、生成带参数二维码应用场景
    微信公众号开发C#系列-10、长链接转短链接
    微信公众号开发C#系列-9、多公众号集中管理
    微信公众号开发C#系列-8、自定义菜单及菜单响应事件的处理
    微信公众号开发C#系列-7、消息管理-接收事件推送
    微信公众号开发C#系列-5、用户和用户组管理-支持同步
  • 原文地址:https://www.cnblogs.com/gryzy/p/7536256.html
Copyright © 2020-2023  润新知