[关闭]
@xiaoziyao 2020-08-08T23:15:38.000000Z 字数 2352 阅读 1041

CF235C Cyclical Quest解题报告

解题报告


CF235C Cyclical Quest解题报告:

更好的阅读体验

题意

题意:给定一个主串个询问串,对于每个询问串,需要求出它所有本质不同循环同构在中出现的次数之和。

数据范围:

分析

一道SAM好题,考察了对DAWG和Parent Tree的理解。

解释循环同构的定义:给定字符串(每个是字符),它的循环同构为:(比如说,的循环同构有)。

考虑循环同构的实质,其实是在前面去除一个字符,并在后面添加一个字符。

在前面去除一个字符?根据endpos和后缀link的性质,一个属于状态的串在前面去除一个字符要么还在这个状态,要么跳后缀link到

在后面添加一个字符?根据DAWG边的定义(其实就是后缀自动机里的边),一个属于状态的串在后面添加字符会跳转到状态

这就比较好办了,我们输入后复制一遍它放在它后面(注意不要复制最后一个字符),这样形成的就会包含的所有循环同构。

然后循环每个字符进行匹配,按照上面的方式跳后缀link和DAWG边,并维护长度,如果长度就记录答案(意味着整个子串都成功匹配),注意记录完答案后需要强制失配,这样就不会让长度(因为的所有循环同构长度都等于,所以如果一定是倍长的锅,比如,倍长后,这会让匹配的长度大于)。

至于本质不同,其实很好处理。我们在每一次记录答案的时候可以作一个标记(我使用的是时间戳标记,这样不需要给数组清空),标记后的结点不对答案做贡献就可以了。

代码

  1. #include<stdio.h>
  2. const int maxn=2000005,maxk=30,maxm=2000005,maxt=2000005;
  3. int i,j,k,m,n,T,tot,last,e,stp,cnt;
  4. int len[maxn],link[maxn],nxt[maxn][maxk],start[maxn],to[maxm],then[maxm],tag[maxn],size[maxn],vis[maxn],s[maxn],t[maxn];
  5. char c;
  6. inline void add(int x,int y){
  7. then[++e]=start[x],start[x]=e,to[e]=y;
  8. }
  9. int extend(int last,int x){
  10. int pos=last,now=++tot,tmp,cln;
  11. tag[now]=1;
  12. len[now]=len[pos]+1;
  13. while(pos!=0&&nxt[pos][x]==0)
  14. nxt[pos][x]=now,pos=link[pos];
  15. if(pos==0){
  16. link[now]=1;
  17. return now;
  18. }
  19. tmp=nxt[pos][x];
  20. if(len[tmp]==len[pos]+1){
  21. link[now]=tmp;
  22. return now;
  23. }
  24. cln=++tot;
  25. len[cln]=len[pos]+1;
  26. for(int i=1;i<=26;i++)
  27. nxt[cln][i]=nxt[tmp][i];
  28. link[cln]=link[tmp],link[tmp]=link[now]=cln;
  29. while(pos!=0&&nxt[pos][x]==tmp)
  30. nxt[pos][x]=cln,pos=link[pos];
  31. return now;
  32. }
  33. void dfs(int x){
  34. size[x]=tag[x];
  35. for(int i=start[x];i;i=then[i]){
  36. int y=to[i];
  37. dfs(y);
  38. size[x]+=size[y];
  39. }
  40. }
  41. int main(){
  42. for(c=getchar();c<'a'||c>'z';c=getchar());
  43. for(;c>='a'&&c<='z';c=getchar())
  44. s[++cnt]=c-96;
  45. last=tot=1;
  46. for(i=1;i<=cnt;i++)
  47. last=extend(last,s[i]);
  48. for(i=2;i<=tot;i++)
  49. add(link[i],i);
  50. dfs(1);
  51. scanf("%d",&T);
  52. while(T--){
  53. int now=1,l=0,ans=0;
  54. cnt=0,stp++;
  55. for(c=getchar();c<'a'||c>'z';c=getchar());
  56. for(;c>='a'&&c<='z';c=getchar())
  57. t[++cnt]=c-96;
  58. for(i=cnt+1;i<2*cnt;i++)
  59. t[i]=t[i-cnt];
  60. for(i=1;i<2*cnt;i++){
  61. while(now!=0&&nxt[now][t[i]]==0)
  62. now=link[now],l=len[now];
  63. if(nxt[now][t[i]])
  64. l++,now=nxt[now][t[i]];
  65. else l=0,now=1;
  66. if(l==cnt){
  67. if(vis[now]!=stp)
  68. vis[now]=stp,ans+=size[now];
  69. if(len[link[now]]+1==cnt)
  70. now=link[now];
  71. l--;
  72. }
  73. }
  74. printf("%d\n",ans);
  75. }
  76. return 0;
  77. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注