zoukankan      html  css  js  c++  java
  • hdu 4622 Reincarnation 字符串hash 模板题

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4622

    题意:给定一个长度不超过2000的字符串,之后有不超过1e5次的区间查询,输出每次查询区间中不同的子串个数?

    做法1:字符串hash

    一般的做法就是模拟每段子串的长度L(从1到 len),这样时间复杂度为O(n^2);但是里面并没有计算子串比较是否相等以及存储的时间,而这段时间就是将字符串看成是“数字”,这样存储和比较的时间均降为O(1)了;

    下面讲讲模板;

    1.如何将字符串看成一个“高精度的数字”,由于相同的子串不只是含有的字符个数的和字符类别要相同,同时还需要和数字一样分成在“什么位”上(如十位还是百位);下面的p[]就是这样一个表示在哪一位;同时s[i]表示的就是子串str[0...i-1],只不过表示成了数字的形式;这样之后就可以直接枚举长度L,并且将是否有重复的给“标记”下来;

    注意:ans[pos][i+L-1] :表示的是只有子串起点在pos(其实之后的二维DP求和可以扩大到更大的区间),终点在i+L-1才需要-1;不是pos+L-1

    2.将上面的标记累加起来,递推出二维的ans[][];即区间长度从小到大递推即可;

     时间空间复杂度均为O(n^2)

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 using namespace std;
     5 #define HASH 10007
     6 #define MAXN 2007
     7 struct StringMap{
     8     int head[HASH],Next[MAXN],tot;
     9     unsigned long long state[MAXN];
    10     int f[MAXN];
    11     void init(){
    12         tot = 0;
    13         memset(head,-1,sizeof(head));
    14     }
    15     int ins(unsigned long long val,int id)
    16     {
    17         int h = val%HASH;
    18         for(int i = head[h];i != -1;i = Next[i]){
    19             if(val == state[i]){
    20                 int tmp = f[i];
    21                 f[i] = id;
    22                 return tmp;
    23             }
    24         }
    25         f[tot] = id;
    26         state[tot] = val;
    27         Next[tot] = head[h];
    28         head[h] = tot++;
    29         return 0;
    30     }
    31 }H;
    32 char str[MAXN];
    33 const int SEED = 13331;
    34 unsigned long long p[MAXN];
    35 unsigned long long s[MAXN];
    36 int ans[MAXN][MAXN];
    37 int main()
    38 {
    39     //freopen("in.txt","r",stdin);
    40     p[0] = 1;
    41     for(int i = 1;i < MAXN;i++)
    42         p[i] = p[i-1]*SEED;
    43     int T;
    44     scanf("%d",&T);
    45     while(T--){
    46         scanf("%s",str);
    47         int len = strlen(str);
    48         s[0] = 0;
    49         for(int i = 1;i <= len;i++)
    50             s[i] = s[i-1]*SEED+str[i-1];
    51         memset(ans,0,sizeof(ans));
    52         for(int L = 1;L <= len;L++){
    53             H.init();
    54             for(int i = 1;i+L-1 <= len;i++){
    55                 int pos = H.ins(s[i+L-1]-s[i-1]*p[L],i);
    56                 ans[i][i+L-1]++;
    57                 ans[pos][i+L-1]--;        //做标记
    58             }
    59         }
    60         for(int i = len;i >= 0;i--)
    61             for(int j = i;j <= len;j++)
    62                 ans[i][j] += ans[i+1][j] + ans[i][j-1] - ans[i+1][j-1];  //递推出所有结果
    63         int Q,l,r;
    64         scanf("%d",&Q);
    65         while(Q--){
    66             scanf("%d%d",&l,&r);
    67             printf("%d
    ",ans[l][r]);
    68         }
    69     }
    70 }
  • 相关阅读:
    Photoshop 基础七 位图 矢量图 栅格化
    Photoshop 基础六 图层
    Warfare And Logistics UVALive
    Walk Through the Forest UVA
    Airport Express UVA
    Guess UVALive
    Play on Words UVA
    The Necklace UVA
    Food Delivery ZOJ
    Brackets Sequence POJ
  • 原文地址:https://www.cnblogs.com/hxer/p/5670347.html
Copyright © 2011-2022 走看看