阿狸的打字机

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\n",ans[i]);
    
    return 0;
}

 

posted on 2017-09-17 17:20  gryzy  阅读(202)  评论(0编辑  收藏  举报

导航