hdu4622(hash解法)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4622
Now you are back,and have a task to do:
Given you a string s consist of lower-case English letters only,denote f(s) as the number of distinct sub-string of s.
And you have some query,each time you should calculate f(s[l...r]), s[l...r] means the sub-string of s start from l end at r.
Input
The first line contains integer T(1<=T<=5), denote the number of the test cases.
For each test cases,the first line contains a string s(1 <= length of s <= 2000).
Denote the length of s by n.
The second line contains an integer Q(1 <= Q <= 10000),denote the number of queries.
Then Q lines follows,each lines contains two integer l, r(1 <= l <= r <= n), denote a query.
For each test cases,the first line contains a string s(1 <= length of s <= 2000).
Denote the length of s by n.
The second line contains an integer Q(1 <= Q <= 10000),denote the number of queries.
Then Q lines follows,each lines contains two integer l, r(1 <= l <= r <= n), denote a query.
Output
For each test cases,for each query,print the answer in one line.
Sample Input
2
bbaba
5
3 4
2 2
2 5
2 4
1 4
baaba
5
3 3
3 4
1 4
3 5
5 5
Sample Output
3
1
7
5
8
1
3
8
5
1
Hint
I won't do anything against hash because I am nice.Of course this problem has a solution that don't rely on hash.题意:查询区间【l,r】的字符串有多少种不同的字串。
解法:这题也可以用后缀自动机解,这里只简单讲一下hash的做法。
首先我们可以枚举区间的长度L,然后枚举区间的起点l。然后我们可以考虑去重的情况,举个栗子吧:比如某字符串为abcabc,我们可以发现abc在区间【1,6】中出现了两次,所以我们应该减掉一个。去重的话,可以利用hash判断当前字符串之前是否出现过,那么问题来了:如果我们定义一个map<ull,int>,来判断的话,可能会出现超时的情况(目前还不知道为啥,难道是使用map的原因吗),做到这里我们可以建一个图,图的边权值为此时字符串的hash值,具体的实现看代码中的注释吧。
#include<iostream> #include<cstring> #include<algorithm> #include<cmath> #include<vector> #include<stack> #include<cstdio> #include<map> #include<set> #include<string> #include<queue> using namespace std; #define inf 0x3f3f3f3f #define ri register int typedef long long ll; typedef unsigned long long ull; inline ll gcd(ll i,ll j){ return j==0?i:gcd(j,i%j); } inline ll lcm(ll i,ll j){ return i/gcd(i,j)*j; } inline void output(int x){ if(x==0){putchar(48);return;} int len=0,dg[20]; while(x>0){dg[++len]=x%10;x/=10;} for(int i=len;i>=1;i--)putchar(dg[i]+48); } inline void read(int &x){ char ch=x=0; int f=1; while(!isdigit(ch)){ ch=getchar(); if(ch=='-'){ f=-1; } } while(isdigit(ch)) x=x*10+ch-'0',ch=getchar(); x=x*f; } const ull p=131; const int maxn=2e3+5; ull bit[maxn]; char ch[maxn];ull ha[maxn]; const ull mod=1e5+7; ull getha(int l,int r){ if(l==r)return ch[l]; return ha[r]-ha[l-1]*bit[r-l+1]; } struct gra{ int head[mod+5]; int pos[maxn];//当前字符出现的最晚的位置 int next[maxn]; ull edg[maxn];//hash值 int num; void init(){ num=0; memset(head,0,sizeof(head)); } int find(ull val,int id){ int u=val%mod; for(int i=head[u];i!=0;i=next[i]){ if(edg[i]==val){ int tem=pos[i]; pos[i]=id; return tem; } } num++; edg[num]=val; pos[num]=id; next[num]=head[u]; head[u]=num; return 0; } }h; int dp[maxn][maxn]; int main(){ int t,q,l,r; scanf("%d",&t); bit[0]=1; for(int i=1;i<maxn;i++){ bit[i]=bit[i-1]*p; } while(t--){ scanf("%s",ch+1); int len=strlen(ch+1); memset(dp,0,sizeof(dp)); ha[0]=1; for(int i=1;i<=len;i++){ ha[i]=ha[i-1]*p+ch[i]; } for(int i=1;i<=len;i++){ h.init(); for(int lm=1;lm+i-1<=len;lm++){ ull tem=getha(lm,lm+i-1); int pos=h.find(tem,lm); dp[pos][lm+i-1]--; dp[lm][lm+i-1]++; } } for(int i=len;i>=1;i--){ for(int j=i+1;j<=len;j++){ dp[i][j]+=dp[i][j-1]+dp[i+1][j]-dp[i+1][j-1]; } } scanf("%d",&q); while(q--){ scanf("%d%d",&l,&r); printf("%d\n",dp[l][r]); } } return 0; }
使用map判重:
建图判重:
(区别太大了吧QAQ)