码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2017-07-22 22:21:15      阅读:209      评论:0      收藏:0      [点我收藏+]

标签:gms   wpf   aac   ora   set   vsp   pts   pll   add   

题目背景

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

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

标签:gms   wpf   aac   ora   set   vsp   pts   pll   add   

原文地址:http://www.cnblogs.com/CzYoL/p/7222775.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!