学了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进制看来从左往右的值和从右往左的值相同,那么它回文。
具体见代码:
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <set>
#include <iostream>
using namespace std;
typedef pair<int,int> pii;
typedef unsigned long long ull;
typedef long long ll; const int bas = ;
const int N = *(int)1e6+; char s[N];
int dp[N]; int main()
{
scanf("%s",s+);
ull pre = s[], suf = s[], mul = ;
int len = strlen(s+);
ll ans = ;
dp[]=; for(int i=;i<=len;i++)
{
mul *= bas;
pre = pre + s[i] * mul;
suf = suf * bas + s[i];
if(pre == suf) dp[i] = dp[i>>] + ;
ans += (ll)dp[i];
}
printf("%I64d\n",ans);
return ;
}