zoukankan      html  css  js  c++  java
  • BZOJ_2434_[NOI2011]_阿狸的打字机_(AC自动机+dfs序+树状数组)

    描述


    http://www.lydsy.com/JudgeOnline/problem.php?id=2434

    给出(n)个字符串,(m)个询问,对于第(i)个询问,求第(x_i)个字符串在第(y_i)个字符串中出现了多少次.

    分析


    首先我们可以想到对于串(x)和串(y),如果(x)在(y)中出现过,那么(x)一定是((y)的某个前缀)的后缀,如果我们用所有字符串建立一个AC自动机,那么对于这个前缀,沿着失配边走,一定能走到(x)串.

    所以我们得到了一个很直观但是复杂度很高的算法:对于每一个询问,枚举(y)中的字符作为前缀的结尾,沿着失配边走,看是否能够走到(x)串,复杂度是(O(mL^2)).显然这种算法是要超时的,我们需要考虑更优的算法.

    这里先介绍fail树这一概念.对于AC自动机上的点(x),我们连一条(f[x] o{x})的有向边,这样就形成了一棵fail树.

    这时我们会发现,之前说的能够沿着失配边找到(x)串的(y)串的后缀,一定在(x)的子树当中.我们用dfs序把树上问题转化为区间问题,问题就转化为了在区间内找符合条件的点有多少个.我们把(y)的后缀标为(1),其他全部标为(0),然后处理所有有关(y)的询问,由于是区间问题,可以用树状数组维护.

    这样的算法的复杂度是(O(mlogn))的.

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 inline int read(int &x){x=0;int k=1;char c;for(c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')k=-1;for(;c>='0'&&c<='9';c=getchar())x=x*10+c-'0';return x*=k;}
      4 
      5 const int maxn=1e5+5,type=26;
      6 int n,qct;
      7 int ans[maxn];
      8 char s[maxn];
      9 struct query{
     10     int x[maxn],next[maxn],hd[maxn];
     11     inline void add_query(int a,int b){
     12         x[++qct]=a; next[qct]=hd[b]; hd[b]=qct;
     13     }
     14 }Q;
     15 struct Aho_Corasick{
     16     int sz,cnt,ect;
     17     int q[maxn],hd[maxn],f[maxn],fa[maxn],val[maxn],pos[maxn],l[maxn],r[maxn],c[maxn<<1];
     18     int ch[maxn][type];
     19     struct edge{
     20         int to,next;
     21         edge(){}
     22         edge(int to,int next):to(to),next(next){}
     23     }g[maxn];
     24     Aho_Corasick(){sz=cnt=0;memset(ch[0],0,sizeof ch[0]);}
     25     inline int id(char c){return c-'a';}
     26     inline int lowbit(int x){return x&-x;}
     27     inline void add_edge(int u,int v){g[++ect]=edge(v,hd[u]);hd[u]=ect;}
     28     inline void build_trie(){
     29         int m=strlen(s+1);
     30         int u=0;
     31         for(int i=1;i<=m;i++){
     32             int c=id(s[i]);
     33             if(c=='P'-'a'){val[u]=++cnt,pos[cnt]=u;continue;}
     34             if(c=='B'-'a'){u=fa[u];continue;}
     35             if(!ch[u][c]){
     36                 memset(ch[++sz],0,sizeof ch[sz]);
     37                 ch[u][c]=sz;
     38                 fa[sz]=u;
     39             }
     40             u=ch[u][c];
     41         }
     42     }
     43     inline void get_fail(){
     44         int L=1,R=0;
     45         for(int c=0;c<type;c++){
     46             int u=ch[0][c];
     47             if(u){f[u]=0;add_edge(0,u);q[++R]=u;}
     48         }
     49         while(L<=R){
     50             int u=q[L++];
     51             for(int c=0;c<type;c++){
     52                 int t=ch[u][c];
     53                 if(!t){ch[u][c]=ch[f[u]][c];continue;}
     54                 int v=f[u];
     55                 f[t]=ch[v][c];
     56                 add_edge(f[t],t);
     57                 q[++R]=t;
     58             }
     59         }
     60     }
     61     void dfs(int x,int &t){
     62         l[x]=++t;
     63         for(int i=hd[x];i;i=g[i].next) dfs(g[i].to,t);
     64         r[x]=++t;
     65     }
     66     inline void add(int x,int d){
     67         int R=sz<<1;
     68         while(x<=R){
     69             c[x]+=d;
     70             x+=lowbit(x);
     71         }
     72     }
     73     inline int sum(int x){
     74         int ret=0;
     75         while(x>0){
     76             ret+=c[x];
     77             x-=lowbit(x);
     78         }
     79         return ret;
     80     }
     81     inline void solve(){
     82         int m=strlen(s+1);
     83         int u=0;
     84         for(int i=1;i<=m;i++){
     85             int c=id(s[i]);
     86             if(c=='B'-'a'){add(l[u],-1);u=fa[u];continue;}
     87             if(c=='P'-'a'){
     88                 int y=val[u];
     89                 for(int j=Q.hd[y];j;j=Q.next[j]){
     90                     int x=Q.x[j];
     91                     ans[j]=sum(r[pos[x]])-sum(l[pos[x]]-1);
     92                 }
     93                 continue;
     94             }
     95             u=ch[u][c];
     96             add(l[u],1);
     97         }
     98     }
     99 }ac;
    100 inline void init(){
    101     scanf("%s",s+1);
    102     ac.build_trie();
    103     read(n);
    104     for(int i=1,a,b;i<=n;i++){
    105         read(a); read(b);
    106         Q.add_query(a,b);
    107     }
    108 }
    109 inline void solve(){
    110     ac.get_fail();
    111     int t=0;
    112     ac.dfs(0,t);
    113     ac.solve();
    114     for(int i=1;i<=n;i++) printf("%d
    ",ans[i]);
    115 }
    116 int main(){
    117     init();
    118     solve();
    119     return 0;
    120 }
    View Code

    2434: [Noi2011]阿狸的打字机

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 2296  Solved: 1298
    [Submit][Status][Discuss]

    Description

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

    经阿狸研究发现,这个打字机是这样工作的:

    l 输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽的最后)。

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

    l 按一下印有'P'的按键,打字机会在纸上打印出凹槽中现有的所有字母并换行,但凹槽中的字母不会消失。

    例如,阿狸输入aPaPBbP,纸上被打印的字符如下:

    a

    aa

    ab

    我们把纸上打印出来的字符串从1开始顺序编号,一直到n。打字机有一个非常有趣的功能,在打字机中暗藏一个带数字的小键盘,在小键盘上输入两个数(x,y)(其中1≤x,y≤n),打字机会显示第x个打印的字符串在第y个打印的字符串中出现了多少次。

    阿狸发现了这个功能以后很兴奋,他想写个程序完成同样的功能,你能帮助他么?

    Input

     输入的第一行包含一个字符串,按阿狸的输入顺序给出所有阿狸输入的字符。

    第二行包含一个整数m,表示询问个数。

    接下来m行描述所有由小键盘输入的询问。其中第i行包含两个整数x, y,表示第i个询问为(x, y)。

    Output

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

    Sample Input

    aPaPBbP

    3

    1 2

    1 3

    2 3

    Sample Output

    2

    1

    0

    HINT

     1<=N<=10^5


    1<=M<=10^5

    输入总长<=10^5

    Source

  • 相关阅读:
    Sql Server数据库快照初探
    RestTemplate的exchange()方法,解决put和delete请求拿不到返回值的问题
    常用 HTTP 状态码
    RestTemplate进行访问分页PageInfo
    Java RestTemplate传递参数
    SQL-----数据库三种删除方式详解
    Mybatis异常-java.lang.IllegalArgumentException: invalid comparison:java.util.Date and java.lang.String
    SpringBoot 项目不加载 application.properties 配置文件
    git设置、查看、取消代理
    Layui:select下拉框回显
  • 原文地址:https://www.cnblogs.com/Sunnie69/p/5647691.html
Copyright © 2011-2022 走看看