码迷,mamicode.com
首页 > 其他好文 > 详细

hdu 4622 Reincarnation 字符串hash 模板题

时间:2016-07-14 15:06:44      阅读:138      评论:0      收藏:0      [点我收藏+]

标签:

题目链接: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\n",ans[l][r]);
68         }
69     }
70 }

 

hdu 4622 Reincarnation 字符串hash 模板题

标签:

原文地址:http://www.cnblogs.com/hxer/p/5670347.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!