【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;
}

时间: 2024-10-10 22:27:06

【NOIP模拟】Grid(字符串哈希)的相关文章

DNA序列 LOJ NOIP模拟赛 D1T1 字符串哈希

字符串哈希 上代码 #include<cstdio> #include<cstring> #include<string> #include<iostream> using namespace std; template<class T> inline void read(T &_a){ bool f=0;int _ch=getchar();_a=0; while(_ch<'0' || _ch>'9'){if(_ch=='-'

NOIP模拟17.8.17

NOIP模拟17.8.17 A 小 G 的字符串文件名 输入文件 输出文件 时间限制 空间限制str.pas/c/cpp str.in str.out 1s 128MB[题目描述]有一天,小 L 给小 G 出了这样一道题:生成一个长度为 n 的.全由小写英文字母构成的字符串,只能使用 k 种字母.要求满足:• 字符串中相邻的两个字母不能相同.• 必须出现恰好 k 种不同的字母.这样的合法字符串可能有很多,小 L 让小 G 输出字典序最小的那个.小 G 太笨啦,不会做这道题,希望你帮帮他.[输入格

NOIP模拟赛 6.29

2017-6-29 NOIP模拟赛 Problem 1 机器人(robot.cpp/c/pas) [题目描述] 早苗入手了最新的Gundam模型.最新款自然有着与以往不同的功能,那就是它能够自动行走,厉害吧. 早苗的新模型可以按照输入的命令进行移动,命令包括‘E’.‘S’.‘W’.‘N’四种,分别对应东南西北.执行某个命令时,它会向对应方向移动一个单位.作为新型机器人,它可以执行命令串.对于输入的命令串,每一秒它会按命令行动一次.执行完命令串的最后一个命令后,会自动从头开始循环.在0时刻时机器人

liu_runda 给辣鸡蒟蒻做的 NOIP模拟赛 1.0 第二题 任(duty) 题解

问题 B: 任(duty) 时间限制: 2 Sec  内存限制: 512 MB 题目描述 liu_runda退役之后就失去梦想开始咸鱼生活了- Bilibili夏日画板活动中,所有人都可以在一块画板上进行像素画创作.UOJ群有一群无聊的人决定在画板上创作一个50*50的UOJ的LOGO.如下图. 这块画板实际上是很大的矩形网格.一个网格是一像素. 一个人每三分钟才能画一个像素.所以liu_runda的咸鱼生活非常无聊. 郭神表示他实在是看不下去liu_rudna这只颓狗了,于是随手出了一道神题,

洛谷——P3370 【模板】字符串哈希

题目描述 如题,给定N个字符串(第i个字符串长度为Mi,字符串内包含数字.大小写字母,大小写敏感),请求出N个字符串中共有多少个不同的字符串. 友情提醒:如果真的想好好练习哈希的话,请自觉,否则请右转PJ试炼场:) 输入输出格式 输入格式: 第一行包含一个整数N,为字符串的个数. 接下来N行每行包含一个字符串,为所提供的字符串. 输出格式: 输出包含一行,包含一个整数,为不同的字符串个数. 输入输出样例 输入样例#1: 5 abc aaaa abc abcc 12345 输出样例#1: 4 说明

字符串哈希(自然溢出模板)

P3370 [模板]字符串哈希 题目描述 如题,给定N个字符串(第i个字符串长度为Mi,字符串内包含数字.大小写字母,大小写敏感),请求出N个字符串中共有多少个不同的字符串. 输入输出格式 输入格式: 第一行包含一个整数N,为字符串的个数. 接下来N行每行包含一个字符串,为所提供的字符串. 输出格式: 输出包含一行,包含一个整数,为不同的字符串个数. 输入输出样例 输入样例#1: 5 abc aaaa abc abcc 12345 输出样例#1: 4 说明 时空限制:1000ms,128M 数据

UvaLive 6439 Pasti Pas! 字符串哈希

链接:http://vjudge.net/problem/viewProblem.action?id=47586 题意:给一个字符串,可以将从前数第i~j和从后数第i~j字符串看作一个字符,问整段字符串看作一个回文里有多少个字符. 思路:字符串哈希,从前开始哈希也从后开始哈希,遇到哈希值相同就多两个字符,最后处理一下中间的字符即可. 代码: #include <iostream> #include <cstdio> #include <cstring> #include

HDU 4821 杭州现场赛:每个片段字符串哈希比较

I - String Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 4821 Description Given a string S and two integers L and M, we consider a substring of S as "recoverable" if and only if (i) I

HDU--4821(字符串哈希)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4821 用到了BKD字符串哈希的方法,一直不是很会哈希,总是用map,但是很显然,map并不是万能的. 用哈希的方法可以递推的求出所有子串的哈希值,最后用map维护答案即可:注意下long long #include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #include&