zoukankan      html  css  js  c++  java
  • 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
    ", x)
    #define Prl(x) printf("%lld
    ",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
  • 相关阅读:
    计算机概念-shell
    数组去重复的三种方法
    CSS 自定义字体
    解决 IE 6/7 中console对象兼容性问题
    Sublime Text 3 Install Markdown Preview Plugins
    对象数组排序函数
    Ubuntu 16.04 下使用Xampp
    JavaScript 中 申明变量的方式--let 语句
    bootstrap框架 导航条组件使用
    phpstorm version 2016.2 License Server激活
  • 原文地址:https://www.cnblogs.com/Hugh-Locke/p/9607426.html
Copyright © 2011-2022 走看看