zoukankan      html  css  js  c++  java
  • HDU 4622 求解区间字符串中的不同子串的个数

     题目大意:

    给定一个长度<2000的串,再给最多可达10000的询问区间,求解区间字符串中的不同子串的个数

    这里先考虑求解一整个字符串的所有不同子串的方法

    对于后缀自动机来说,我们动态往里添加一个字符,每次添加一个字符进去,我们只考虑那个生成的长度为当前长度的后缀自动机的节点

    那么这个节点可接收的字符串的个数就是( p->l - p->f->l ),也就是以当前点为最后节点所能得到的与之前不重复的子串的个数

    那么这个问题就很好解决了,共2000个位置,以每一个位置为起点构建一次后缀自动机,一直构建到最后一个字符,过程中不断记录所能得到的子串个数

    把这个个数动态保存到f[][]数组中

    那么打好了表,最后询问的时候,直接访问这个f[][]即可

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 #include <algorithm>
     5 
     6 using namespace std;
     7 #define N 2005
     8 #define M 26
     9 struct SamNode{
    10     SamNode *son[M] , *f;
    11     int l;
    12     void init(){
    13         for(int i=0 ; i<M ; i++) son[i] = NULL;
    14         f=NULL , l=0;
    15     }
    16 }sam[N<<1] , *root , *last;
    17 
    18 int cnt , f[N][N] , ret;
    19 char s[N] ;
    20 
    21 void init(){
    22     sam[0].init();
    23     root = last = &sam[cnt=0];
    24 }
    25 
    26 void add(int x)
    27 {
    28     SamNode *p = &sam[++cnt] , *jp=last;
    29     p->init();
    30     p->l = jp->l+1;
    31     last = p;
    32     for(; jp&&!jp->son[x] ; jp=jp->f) jp->son[x] = p;
    33     if(!jp) p->f = root;
    34     else{
    35         if(jp->l+1 == jp->son[x]->l) p->f = jp->son[x];
    36         else{
    37             SamNode *r = &sam[++cnt] , *q = jp->son[x];
    38             r->init();
    39             *r = *q; r->l = jp->l+1;
    40             p->f = q->f = r;
    41             for( ; jp&&jp->son[x]==q ; jp=jp->f) jp->son[x] = r;
    42         }
    43     }
    44     ret += p->l-(p->f->l);
    45 }
    46 
    47 void solve()
    48 {
    49     int len = strlen(s);
    50     for(int i=0 ; i<len ; i++){
    51         ret = 0;
    52         init();
    53         for(int j=i ; j<len ; j++){
    54             add(s[j]-'a');
    55             f[i][j] = ret;
    56         }
    57     }
    58 }
    59 
    60 int main()
    61 {
    62   //  freopen("a.in" , "r" , stdin);
    63     int T;
    64     scanf("%d" , &T);
    65     while(T--)
    66     {
    67         scanf("%s", s);
    68         int m , l , r;
    69         scanf("%d" , &m);
    70         solve();
    71         while(m--){
    72             scanf("%d%d" , &l , &r);
    73             printf("%d
    " , f[l-1][r-1]);
    74         }
    75     }
    76     return 0;
    77 }
  • 相关阅读:
    C# 日期帮助类【原创】
    C# 发送邮件
    每日一题力扣453
    每日力扣628
    每日一题力扣41巨坑
    每日一题力扣274
    每日一题力扣442有坑
    每日一题力扣495
    每日一题力扣645
    每日一题力扣697
  • 原文地址:https://www.cnblogs.com/CSU3901130321/p/4596687.html
Copyright © 2011-2022 走看看