学了kmp之后又学了hash来搞字符串。这东西很巧妙,且听娓娓道来。

  这题的题意是:一个字符串如果是回文的,那么k值加1,如果前一半的串也是回文,k值再加1,以此类推,算出其k值。打个比方abaaba,k值为3,abaxxaba,k值为1。现在,给出一个串,让你求这个串的所有前缀(包括本身)的k值的和。

  如果考虑马拉车,那么先预处理出每个地方的最长回文长度,然后不断的截断,如果子串的回文长度大于其回文长度,那么k值加1,这样即可。但是马拉车写起来比较繁琐,没有模板我也没法手写。

  这里提供hash的方法。hash的方法就是给出一个素数,我这里是使用的17,然后就把字符串当做17进制,把每个位置的值和反过来计算的这个位置的值计算出来,然后每位一比对,如果相同,就在此处回文(显然,复杂度是O(n))。不过我觉得17可能不妥,因为s[i]的上限值是127,那么这个素数应当大于127才好,这里先暂时这样吧,如果不行就换233好了- 。-

  这东西怎么理解呢,打个比方121,在10进制看来从左往右的值和从右往左的值相同,那么它回文。

  具体见代码:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 #include <set>
 5 #include <iostream>
 6 using namespace std;
 7 typedef pair<int,int> pii;
 8 typedef unsigned long long ull;
 9 typedef long long ll;
10 
11 const int bas = 17;
12 const int N = 5*(int)1e6+5;
13 
14 char s[N];
15 int dp[N];
16 
17 int main()
18 {
19     scanf("%s",s+1);
20     ull pre = s[1], suf = s[1], mul = 1;
21     int len = strlen(s+1);
22     ll ans = 1;
23     dp[1]=1;
24 
25     for(int i=2;i<=len;i++)
26     {
27         mul *= bas;
28         pre = pre + s[i] * mul;
29         suf = suf * bas + s[i];
30         if(pre == suf) dp[i] = dp[i>>1] + 1;
31         ans += (ll)dp[i];
32     }
33     printf("%I64d\n",ans);
34     return 0;
35 }