• 【NOIP模拟】Grid(字符串哈希)


    题目背景

    SOURCE:NOIP2016-RZZ-1 T3

    题目描述

    有一个 2×N 的矩阵,矩阵的每个位置上都是一个英文小写字符。

    现在需要从某一个位置开始,每次可以移动到一个没有到过的相邻位置,即从 (i,j) 可以移动到 (i-1,j)(i+1,j)(i,j-1)(i,j+1) (要求该位置在矩阵上且之前没有到过)。

    从选取的起点开始,经过 2N-1 次移动后,将会走过矩阵的每一个位置,将移动经过的格子依次取出来就得到了一个长度为 2N 的串。

    可以任意选择起点和终点,任意选择移动方案,求能得到多少种不同的串。

    输入格式

    输入第一行,一个正整数 N 。
    接下来两行,每行一个由英文小写字符组成的字符串,描述这个矩阵。

    输出格式

    输出一行一个整数,表示能得到的串的总数。

    样例数据 1

    输入



    a

    输出

    1

    样例数据 2

    输入


    dab 
    abd

    输出

    8

    样例数据 3

    输入


    ababa 
    babab

    输出

    2

    备注

    【样例2说明】

    能得到的字符串有:abdbad, adabdb, badabd, bdbada, dababd, dabdba, dbabad, dbadab。

    【数据规模与约定】

    对于 20% 的数据,N≤5。
    对于 60% 的数据,N≤50。
    对于 100% 的数据,N≤600。

    【题目分析】

    没怎么做过字符串哈希的题目,这次就当是预习了。

    因为题目中要求不能走已经走过的地方,并且要将整个矩阵走完,那么整个问题就有套路了。

    走法都是固定的:

    从某一点出发,向左或向右走到头,再拐回到同一列,然后从下一列开始可以选择走若干个蛇形(可以是$0$),然后迂回。

    如下图所示:

    $........$

    当然方向不止这几种,哈希时进行$4$次反转即可。

     

    下面来看看哈希:

    整个图形可以看成三部分:左边迂回的部分,中间蛇形的部分,右边迂回的部分。

    我们可以将左边迂回部分的哈希值预处理出来,然后枚举右边迂回的部分,每次拼接一个蛇形,再拼接上左边的部分。

    注意在将右边和蛇形与左边拼接时,因为已经预处理出了左边,所以只需将右边加蛇形的哈希值乘上$Powh[2 * (j - 1)]$再加上左边的哈希值(j的含义看代码,具体为什么乘以可以试着写写没有预处理时的计算式子)。

    【CODE】

      下面是单哈希的代码。

    #include<iostream>
    #include<cstring>
    #include<string>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<vector>
    using namespace std;
    
    const int h = 2333, H = 2333333;
    int n;
    char s[5][2000];
    unsigned long long num[6000600];
    unsigned long long l[5][2000];
    unsigned long long Powh[2000];
    unsigned long long now;
    int fst[2400000], nxt[6000600], tot;
    
    inline void insert(unsigned long long x){
        int i, y = x % H;
        for(i = fst[y]; i; i = nxt[i])
            if(num[i] == x) return;
        num[++tot] = x;
        nxt[tot] = fst[y];
        fst[y] = tot;
    }
    
    int main(){
        int i, j; 
        for(Powh[0] = i = 1; i <= 1300; i++)
            Powh[i] = Powh[i - 1] * h;
        scanf("%d", &n);
        scanf("%s", s[1] + 1);
        scanf("%s", s[2] + 1);
        tot = 0;
        for(int T = 1; T <= 4; T++){
            for(i = 1; i <= n; i++){
                l[1][i] = l[2][i] = 0;
                for(j = i; j >= 1; j--) l[1][i] = l[1][i] * h + s[1][j];
                for(j = 1; j <= i; j++) l[1][i] = l[1][i] * h + s[2][j]; 
                for(j = i; j >= 1; j--) l[2][i] = l[2][i] * h + s[2][j];
                for(j = 1; j <= i; j++) l[2][i] = l[2][i] * h + s[1][j];
            }
            int k;
            for(i = 1; i <= n; i++){
                now = 0;
                for(j = i; j <= n; j++) now = now * h + s[1][j];
                for(j = n; j >= i; j--) now = now * h + s[2][j];
                k = 2;
                for(j = i; j >= 1; j--){
                    insert(l[k][j - 1] + now * Powh[2 * (j - 1)]);
                    now = now * h + s[k][j - 1];
                    k = 3 - k;
                    now = now * h + s[k][j - 1];
                }
            }
            
            for(i = 1; i <= n; i++) swap(s[1][i], s[2][i]);
            if(T == 2){
                for(i = 1; i <= n / 2; i++){
                    swap(s[1][n - i + 1] , s[1][i]);
                    swap(s[2][n - i + 1] , s[2][i]);
                }
            }
        }
        cout<<tot<<endl;
        return 0;
    }
    View Code
  • 相关阅读:
    python_day06(ip代理池)
    二叉树的层次遍历之队列的使用
    推荐系统实战笔记 1.1什么是推荐系统
    牛顿法求平方根可拓展
    java LinkedHashMap实现LRUCache缓存
    交换两个变量常规四种做法
    交换两个变量之移位交换法
    推荐系统实战笔记01--前言
    Ubuntu 14.04更新为国内阿里源解决apt-get install无法执行的问题
    求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
  • 原文地址:https://www.cnblogs.com/CzYoL/p/7222775.html
Copyright © 2020-2023  润新知