CodeForces7D 字符串hash + dp

https://cn.vjudge.net/problem/20907/origin

长度是 n 的字符串 s,如果它自身是回文数,且它的长度为  的前缀和后缀是 (k - 1)-回文数,则它被称作 k-回文数。按照定义,任何字符串 (甚至空字符串) 都是 0-回文数。

字符串 s 的回文度,被定义为这样的一个最大数 k,满足 s 是 k-回文数。例如,"abaaba" 具有的回文度是 3 。

给定一个字符串。您的任务是,找出它的全部前缀的回文度之和。

输入
输入数据的第一行,包含了一个非空的字符串,由拉丁字母和数字组成。字符串的长度,不超过 5·106 。字符串是大小写敏感的。

输出
输出仅有的一个数 — 字符串的全部前缀的回文度之和。
题意

当我们想到用dp思想的时候,问题就转化为了求这个字符串每一个前缀是否是回文串的问题。

字符串hash其实和进制进位有一些相似,我们想到了这一点就可以线性的时间正着求前缀字符串的hash值和前缀字符串的倒转的hash值

当我们求正序前缀的hash的时候,每一次操作就相当于再字符串的最前面插入一个值,所以我们要首先处理出每一位的指数级ans,然后f[i] = f[i - 1] + str[i] * ans;

当我们求逆序前缀的hash值的时候,每一次操作就相当于在字符串的最后插入一个值,整个字符串就要左移一位然后把这个位塞进去 也就是f [i]= f[i - 1] * tmp + str[i];

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)  
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))  
#define Sca(x) scanf("%d", &x)
#define Scl(x) scanf("%lld",&x);  
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);  
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long  
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second 
typedef vector<int> VI;
const double eps = 1e-9;
const int maxn = 5e6 + 10;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7; 
int N,M,tmp,K; 
char str[maxn];
int dp[maxn];
ULL f1[maxn],f2[maxn];
int main()
{
    scanf("%s",str + 1);
    int l = strlen(str + 1);
    ULL ans = 1;
    LL sum = 0;
    dp[0] = 0;
    for(int i = 1 ; i <= l; i ++){
        if(str[i] >= '0' && str[i] <= '9'){
            str[i] = str[i] - '0';
        }else if(str[i] >= 'a' && str[i] <= 'z'){
            str[i] = str[i] - 'a' + 10;
        }else{
            str[i] = str[i] - 'A' + 36;
        }
        f1[i] = f1[i - 1] * 131 + str[i];
        f2[i] = (f2[i - 1] + str[i] * ans);
        ans *= 131;
        if(f1[i] == f2[i]){
            dp[i] = dp[i >> 1] + 1;
            sum += dp[i];
        }
    }
    Prl(sum);
    
    #ifdef VSCode
    system("pause");
    #endif
    return 0;
}
View Code

 

posted @ 2018-09-07 22:35  Hugh_Locke  阅读(266)  评论(0编辑  收藏  举报