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 }
  • 相关阅读:
    Eloquent ORM模型中添加自定义值
    wget
    带坑的几道PHP面试题
    php字符型转整型
    SELECT 1
    GD库
    Windows下.svn文件夹的最简易删除方法(附linux)
    svn 撤销修改
    mysql应用基本操作语句(转)
    i春秋broken
  • 原文地址:https://www.cnblogs.com/hxer/p/5670347.html
Copyright © 2011-2022 走看看