• 2022牛客多校九 G-Magic Spells(manacher+双哈希)


    题目链接:登录—专业IT笔试面试备考平台_牛客网

    题目:

     样例输入:

    1. 3
    2. abaca
    3. abccaca
    4. acabb

    样例输出:

    4

    题意:首先给定一个n,然后给定n个字符串,求出有多少个字符串满足是回文串而且是n个字符串的子串。

    这道题可以用回文树来求解,但我还不会,下面我用manacher加双哈希来写一下这道题目的思路。不懂manacher算法的小伙伴可以看下这里:Manacher(求解最长回文子串)_AC__dream的博客-CSDN博客

    首先要理解manacher求解最长回文子串长度的原理,其实manacher是能够处理出来以所有字符为中心的最长回文子串能够扩展的长度,整个字符串的最长回文子串只不过是以每个字符为中心的最长回文子串长度的最大值而已。他的复杂度是O(n)的,也就是说他扩展的次数就是O(n)的,而我们这道题需要预处理出来每个字符串中本质不同的回文子串的个数,由于在manacher算法求解p数组时我们用到了对称性,在这里我们依旧可以用一下对称性,假如以当前字符为中心的回文子串最大扩展长度通过对称性得到了的是x,我们还需要在x的基础上继续扩展,那么说明以当前字符为中心的长度为x的回文子串都已经在前面记录过了,所以肯定不会是与之前本质不同的回文串,我们无需再做记录,我们只需要判断暴力扩展的字符串是否为本质不同的回文串即可,判断方法为双哈希,但是需要注意的是双哈希不能让unsigned long long自然溢出,这道题会卡这个,我双哈希设置了两个模数,一个是1e9+7,另一个是1e9+11,双哈希就是把两个哈希值看作一个pair,并用一个map记录pair的出现次数即可,这样我们就可以求出每个串中本质不同的回文字符串出现的次数,我们存进去一个map,保证每个字符串中回文字符串只会记录进map一次,那么最后我们统计map中每个字符串出现的次数,当出现次数等于n时代表每个字符串都有该子串,计入答案即可。

    细节见代码:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. using namespace std;
    11. typedef pair<long long,long long>PII;
    12. const int N=6e5+10,mod1=1e9+7,mod2=1e9+11;
    13. mapint>mp;
    14. char s[10][N];
    15. long long h1[10][N],h2[10][N],P1[N],P2[N];
    16. char t[N];
    17. int p[N];
    18. long long ha1(int id,int l,int r)
    19. {
    20. return (h1[id][r]-(h1[id][l-1]*P1[r-l+1])%mod1+mod1)%mod1;
    21. }
    22. long long ha2(int id,int l,int r)
    23. {
    24. return (h2[id][r]-(h2[id][l-1]*P2[r-l+1])%mod2+mod2)%mod2;
    25. }
    26. void manacher(int o,char s[])
    27. {
    28. int n=strlen(s+1);
    29. for(int i=n;i>=0;i--)
    30. {
    31. p[i*2+1]=p[i*2]=0;
    32. t[i*2+1]='#';
    33. t[i*2]=s[i];
    34. }
    35. mapint>mpp;
    36. t[0]='$';
    37. int mx=0,id=0;
    38. for(int i=1;i<=2*n+1;i++)
    39. {
    40. if(imin(p[2*id-i],mx-i);
    41. else p[i]=1;
    42. while(i>p[i]&&t[i-p[i]]==t[i+p[i]])
    43. {
    44. if(t[i]=='#')//偶数长度
    45. {
    46. int tt=p[i]>>1;
    47. if(tt==0)
    48. {
    49. p[i]++;
    50. continue;
    51. }
    52. int tid=(i-1)/2;//对应于原字符串左中心
    53. if(!mpp[{ha1(o,tid-tt+1,tid+tt),ha2(o,tid-tt+1,tid+tt)}])
    54. {
    55. mpp[{ha1(o,tid-tt+1,tid+tt),ha2(o,tid-tt+1,tid+tt)}]++;
    56. mp[{ha1(o,tid-tt+1,tid+tt),ha2(o,tid-tt+1,tid+tt)}]++;
    57. }
    58. }
    59. else//奇数长度
    60. {
    61. int tt=(p[i]+1)/2;
    62. int tid=i/2;
    63. if(!mpp[{ha1(o,tid-tt+1,tid+tt-1),ha2(o,tid-tt+1,tid+tt-1)}])
    64. {
    65. mpp[{ha1(o,tid-tt+1,tid+tt-1),ha2(o,tid-tt+1,tid+tt-1)}]++;
    66. mp[{ha1(o,tid-tt+1,tid+tt-1),ha2(o,tid-tt+1,tid+tt-1)}]++;
    67. }
    68. }
    69. p[i]++;
    70. }
    71. if(i+p[i]>mx)
    72. {
    73. mx=i+p[i];
    74. id=i;
    75. }
    76. }
    77. }
    78. int main()
    79. {
    80. int T;
    81. P1[0]=P2[0]=1;
    82. for(int i=1;i-1]*131)%mod1,P2[i]=(P2[i-1]*13331)%mod2;
    83. int n;
    84. scanf("%d",&n);
    85. for(int i=1;i<=n;i++)
    86. {
    87. scanf("%s",s[i]+1);
    88. for(int j=1;j<=strlen(s[i]+1);j++)
    89. {
    90. h1[i][j]=(h1[i][j-1]*131+s[i][j])%mod1;
    91. h2[i][j]=(h2[i][j-1]*13331+s[i][j])%mod2;
    92. }
    93. manacher(i,s[i]);
    94. }
    95. long long ans=0;
    96. for(mapint>::iterator it=mp.begin();it!=mp.end();it++)
    97. if(it->second==n) ans++;
    98. printf("%lld",ans);
    99. return 0;
    100. }

  • 相关阅读:
    Linux存储管理磁盘分区逻辑分区
    常见负载均衡服务器介绍
    MySQL之账号管理、建库以及四大引擎
    pygame实现物体运动拖尾尾迹-渐隐版
    以太坊学习二:签名
    【机器学习】:如何对你的数据进行分类?
    onnx-modifier使用
    YTM32的电源管理与低功耗系统详解
    【探花交友】项目介绍
    专利申请说明
  • 原文地址:https://blog.csdn.net/AC__dream/article/details/126354272