【泉州一中国庆集训day6】String
2016-10-30 15:15
387 查看
题目链接:http://v.qzyz.com/contest/293/problem/3
题目大意:给定一个长度为N的字符串S,有Q组询问,对于每组询问l和r,求字符串S有多少字串T与G=S[l,r]相似。相似的定义:两个字符串的长度len相等,对于任意i<=len,j<=len,满足Ti=Tj且Gi=Gj,或者Ti≠Tj且Gi≠Gj。
数据范围:N,Q<=50 000,字符集为(a,b,c,d,e,f,g,h,i,j)
题解:对于判断字符串相等的问题通常用哈希来求解。在本题中,两个字符串并不要求相等,只需要字母一一对应即可。我们记一个数组a,表示S中与当前位置字符相同的上一个位置的距离,即找到最小的a[i]使得S[i-a[i]]=S[i]。那么两个字符串相似就说明a相等。但是我们注意到,在每个字符第一次出现的位置,a的值不需要相等,我们把这些位置称为特殊点,在两个相似的字符串中,特殊点的位置也应该一一对应。由于字符集大小只有10,所以这样的点最多只有10个。
我们可以给数组a的所有后缀排个序,在比较两个后缀的时候,先找出所有的特殊点,把这些点的位置上的a当成0,然后进行比对。
具体的比较方法是:找出两个串的所有特殊点并排序,然后从前往后比较,直到找到第一个 i 满足两个串的第i+1个特殊点位置不一样或者第i个和第i+1个特殊点之间的串的hash值不一样。然后从第 i 个特殊点的位置起,二分两个串的最长公共前缀长度z,比较两个串的第z+1个位置。如果有一个串的第z+1个位置是特殊点(前面说了当成0),那么该串排前面,否则直接比较两个串的第z+1个位置的a值。如果直到其中一个串结束时两串仍然相等,那么较短的串排前面。
排好顺序后,对于询问 l 和 r ,从以第 l 个位置开始的后缀所在的排名分别往前后二分出左右端点,使得它们的最长公共前缀大于等于r-l+1,即可统计出答案。
时间复杂度O(10nlog^2n(排序)+10nlogn(询问))
(ps:在本题中我是使用了107作为底数和自然溢出来哈希并成功卡过了所有数据,但是建议读者还是多选几个数作为底数或者取模来提高正确率,否则说不定什么时候就被卡了。话说明明上周就想写这篇题解了我是怎么拖到现在的难得我还记得hhhh)
代码如下:
题目大意:给定一个长度为N的字符串S,有Q组询问,对于每组询问l和r,求字符串S有多少字串T与G=S[l,r]相似。相似的定义:两个字符串的长度len相等,对于任意i<=len,j<=len,满足Ti=Tj且Gi=Gj,或者Ti≠Tj且Gi≠Gj。
数据范围:N,Q<=50 000,字符集为(a,b,c,d,e,f,g,h,i,j)
题解:对于判断字符串相等的问题通常用哈希来求解。在本题中,两个字符串并不要求相等,只需要字母一一对应即可。我们记一个数组a,表示S中与当前位置字符相同的上一个位置的距离,即找到最小的a[i]使得S[i-a[i]]=S[i]。那么两个字符串相似就说明a相等。但是我们注意到,在每个字符第一次出现的位置,a的值不需要相等,我们把这些位置称为特殊点,在两个相似的字符串中,特殊点的位置也应该一一对应。由于字符集大小只有10,所以这样的点最多只有10个。
我们可以给数组a的所有后缀排个序,在比较两个后缀的时候,先找出所有的特殊点,把这些点的位置上的a当成0,然后进行比对。
具体的比较方法是:找出两个串的所有特殊点并排序,然后从前往后比较,直到找到第一个 i 满足两个串的第i+1个特殊点位置不一样或者第i个和第i+1个特殊点之间的串的hash值不一样。然后从第 i 个特殊点的位置起,二分两个串的最长公共前缀长度z,比较两个串的第z+1个位置。如果有一个串的第z+1个位置是特殊点(前面说了当成0),那么该串排前面,否则直接比较两个串的第z+1个位置的a值。如果直到其中一个串结束时两串仍然相等,那么较短的串排前面。
排好顺序后,对于询问 l 和 r ,从以第 l 个位置开始的后缀所在的排名分别往前后二分出左右端点,使得它们的最长公共前缀大于等于r-l+1,即可统计出答案。
时间复杂度O(10nlog^2n(排序)+10nlogn(询问))
(ps:在本题中我是使用了107作为底数和自然溢出来哈希并成功卡过了所有数据,但是建议读者还是多选几个数作为底数或者取模来提高正确率,否则说不定什么时候就被卡了。话说明明上周就想写这篇题解了我是怎么拖到现在的难得我还记得hhhh)
代码如下:
#include <algorithm> #include <cstring> #include <cstdio> using namespace std; const int p=107; int a[50005],b[10],c[50005][10],d[50005],f[50005],g[50005],s[50005], h[50005],i,n,q,j,x,y; char ch; bool Same(int x,int y,int len) { return f[x+len]-f[x]*g[len]==f[y+len]-f[y]*g[len]; } bool check(int x,int y,int len) { if (x+len>n || y+len>n) return 0; int a1[10],a2[10],i; for (i=0;i<10;++i) { if (s[x]!=i) a1[i]=c[x][i]-x;else a1[i]=len+1; if (s[y]!=i) a2[i]=c[y][i]-y;else a2[i]=len+1; } sort(a1,a1+10); sort(a2,a2+10); int z=0; for (i=0;i<10 && a1[i]==a2[i] && a1[i]<=len+1;++i) if (z!=a1[i] && !Same(x+z,y+z,a1[i]-1-z)) return 0; else if ((z=a1[i])>len) return 1; return 0; } int lcp(int x,int y) { int l=1,r=n-max(x,y),mid,z=0; for (;l<=r;) { mid=(l+r)>>1; if (Same(x,y,mid)) z=mid,l=mid+1; else r=mid-1; } return z; } bool cmp(int x,int y) { int a1[10],a2[10],i; for (i=0;i<10;++i) { if (s[x]!=i) a1[i]=c[x][i]-x;else a1[i]=n+1-x; if (s[y]!=i) a2[i]=c[y][i]-y;else a2[i]=n+1-y; } sort(a1,a1+10); sort(a2,a2+10); int z=0; for (i=0;i<10 && a1[i]==a2[i];++i) if (z!=a1[i] && !Same(x+z,y+z,a1[i]-1-z)) break;else z=a1[i]; if (x+z>n || y+z>n) return x+z>n; z+=lcp(x+z,y+z); if (x+z>=n || y+z>=n) return x+z>=n; if (z+1==a1[i] || z+1==a2[i]) return z+1==a1[i]; return a[x+z+1]<a[y+z+1]; } int main() { scanf("%d%d\n",&n,&q); for (i=1;i<=n;++i) { scanf("%c",&ch); s[i]=ch-'a'; } scanf("\n"); g[0]=1;f[0]=0; for (i=1;i<=n;++i) { a[i]=i-b[s[i]]; b[s[i]]=i; f[i]=f[i-1]*p+a[i]; g[i]=g[i-1]*p; } for (i=0;i<10;++i) c[n+1][i]=n+1; for (i=n;i>=0;--i) { for (j=0;j<10;++j) c[i][j]=c[i+1][j]; c[i][s[i]]=i; } for (i=1;i<=n;++i) d[i]=i; sort(d+1,d+n+1,cmp); for (i=1;i<=n;++i) h[d[i]]=i; for (i=1;i<=q;++i) { scanf("%d%d\n",&x,&y);y-=x;x=h[x]; int l=1,r=x-1,mid,ansl=x,ansr=x; for (;l<=r;) { mid=(l+r)>>1; if (check(d[x],d[mid],y)) ansl=mid,r=mid-1; else l=mid+1; } l=x+1;r=n; for (;l<=r;) { mid=(l+r)>>1; if (check(d[x],d[mid],y)) ansr=mid,l=mid+1; else r=mid-1; } printf("%d\n",ansr-ansl+1); } return 0; }
相关文章推荐
- 国庆集训day6 T2 欧拉函数求互质数个数
- 【泉州一中国庆集训day4】书稿
- 【泉州一中国庆集训day4】破解
- 【泉州一中国庆集训day5】label
- 【扬中集训Day6T1】 白日梦
- NOIP2017 国庆郑州集训知识梳理汇总
- [莫队维护DP] LOJ#6074. 「2017 山东一轮集训 Day6」子序列
- 国庆七天乐 Day6
- leetcode day6 -- String to Integer (atoi) && Best Time to Buy and Sell Stock I II III
- 省队集训day6 C
- 省队集训day6 A
- 寒假▪福州集训 Day6
- NOIP2017 国庆郑州集训知识梳理汇总
- 2017国庆 雅礼集训 题解合集
- AYIT2016省赛集训第五周H - String to Palindrome(dp)
- 1/20集训一 STL C. (set/map +string 找单词按字典序排列) Andy's First Dictionary
- nyist-ACM17新生国庆集训Round#1题解
- 国庆音标集训
- 2016国庆集训day3-minimum.cpp
- 集训final D STL中string的应用