题解-Reachable Strings

前置知识:

\(\texttt{Hash}\)


Reachable Strings

给一个长度为 \(n\) 的 \(\texttt{01}\) 串 \(s\),可以让 \(s\) 中的 \(\texttt{110}\) 和 \(\texttt{011}\) 互相转换。\(q\) 次询问,每次给定两个 \(s\) 的子串 \(s_{l_1\sim l_1+len-1}\) 和 \(s_{l_2\sim l_2+len-1}\),问两个串是否可以互相变换得到。

数据范围:\(1\le n,q\le 10^5\)。


哈希萌新觉得这是哈希好题。


很容易注意到 \(\texttt{11}\color{#9c3}{\texttt{0}}\leftrightarrow\color{#9c3}{\texttt{0}}\texttt{11}\) 就是 \(\texttt{0}\) 左右移动两个位置

但是不可以 \(\texttt{10}\color{#9c3}{\texttt{0}}\leftrightarrow\color{#9c3}{\texttt{0}}\texttt{01}\) 或 \(\texttt{01}\color{#9c3}{\texttt{0}}\leftrightarrow\color{#9c3}{\texttt{0}}\texttt{10}\),说明 \(\texttt{0}\) 移动时不能跨越别的 \(\texttt{0}\)

综上,所有 \(\texttt{0}\) 的位置(从左往右第几个 \(\texttt{0}\)) 不会发生改变,并且下标的奇偶性不会变。

所以可以把所有 \(\texttt{0}\) 按序记录下标奇偶性生成序列,然后判断 两个子序列 是否可以互相变换得到 可以用序列哈希对比 看是否相等

重点是因为每个子序列的起点奇偶性不都相同,所以每个 \(0\) 有两种奇偶性可能,所以用两个哈希数组。


具体实现哈希时可以用一个质数进制数来表示一个序列。

如果从高到低第 \(i\) 位为 \(1\),就表示原字符串从左到右第 \(i\) 个 \(\texttt{0}\) 的下标为奇数;如果为 \(2\),就表示原字符串从左到右第 \(i\) 个 \(\texttt{0}\) 的下标为偶数

然后开前缀 \(\texttt{0}\) 序列数组 \(h\),\(h_n\) 表示原字符串前 \(n\) 个 \(\texttt{0}\) 哈希得的质数进制数。

因为子序列的起点奇偶性不同,所以有两个 \(h\),分别表示以起点为奇数和偶数为标准时哈希得的前缀 \(\texttt{0}\) 序列数组。

子串可以由前缀 \(\texttt{0}\) 序列数组推得,看是否可以互相变换得到只需直接比较子串。

但是有个问题:\(0\) 那么多,形成的质数进制数太大怎么办(远爆 \(\texttt{long long}\))?

解决方法是模某个大质数(如 \(998244353\))。虽然这样可能会把两个不同的序列哈希得一样,但这正是哈希的精髓。没有绝对正确的哈希,能解决问题的就是好哈希。


Code

#include <bits/stdc++.h>
using namespace std; //&Start
#define inf 0x3f3f3f3f
#define re register
#define il inline
#define hash unorded_map
typedef long long lng;
typedef unsigned long long ulng;
typedef vector<int> veci;
#define fo(i,st,xb,y) for(re int i=st;i xb;i y) //&Data
#define N 200000
#define mod 998244353 //模数为998244353
#define base 5119 //5119进制
char s[N+10];
int n,m,h[N+10][2],bs[N+10]={1},ze[N+10];
//两个h,进制前缀积,零数量前缀和 //&Main
il int Hash(re int l,re int r,re int o){return (-1ll*h[l-1][o]*bs[ze[r]-ze[l-1]]%mod+h[r][o]+mod)%mod;} //子序列哈希值
int main(){
scanf("%d%s",&n,s+1);
fo(i,1,<=n,++)
if(s[i]=='1') h[i][0]=h[i-1][0],h[i][1]=h[i-1][1],ze[i]=ze[i-1];
else h[i][0]=(1ll*h[i-1][0]*base%mod+1+(i&1))%mod,
h[i][1]=(1ll*h[i-1][1]*base%mod+1+((i&1)^1))%mod,ze[i]=ze[i-1]+1;
fo(i,1,<=n,++) bs[i]=1ll*bs[i-1]*base%mod;
scanf("%d",&m); fo(i,1,<=m,++){
re int l1,l2,len; scanf("%d%d%d",&l1,&l2,&len);
(Hash(l1,l1+len-1,l1&1)==Hash(l2,l2+len-1,l2&1)?puts("Yes"):puts("No"));
}
return 0;
}

祝大家学习愉快!

最新文章

  1. .Net 跨平台可移植类库正在进行
  2. Java多线程---同步与锁
  3. Android ActionBar Home按钮返回事件处理的两种方式
  4. 解析XML的几种方法之SAX解析
  5. Poj(3687),拓扑排序,
  6. logcat保存当前应用程序的日志并上传服务器或指定邮箱
  7. python chanllenge题解
  8. WebForm页面生命周期WEBFORM_ASPNET控件树的生成和作用
  9. 比较JqGrid与XtraGrid
  10. T-SQL动态查询(1)——简介
  11. Entity Framework入门教程(13)---EF中的高并发
  12. 《XXX重大技术需求征集系统》的可用性和可修改性战术分析
  13. EntityFramework Core并发深挖详解,一纸长文,你准备好看完了吗?
  14. ImageMagick: win7 | win8 &amp; uac (用户帐户控制) 注册表的一些事
  15. pythone函数基础(9)操作数据库连接
  16. python装饰器带括号和不带括号的语法和用法
  17. 低版本系统兼容的ActionBar(二)ActionProvider+分离式ActionBar+分离式的ActionMode
  18. Chrome DevTools 的 Sources 调试
  19. 从解决一个java.lang.NoSuchMethodError想到的
  20. 权限验证AuthorizeAttribute

热门文章

  1. Java的注释-标识符和关键字
  2. 【译】Arc 在 Rust 中是如何工作的
  3. Java从后端下载文件到浏览器
  4. 「NOIP2009」最优贸易 题解
  5. scrapy学习之爬虫练习平台35
  6. 前端web安全-CSRF基础入门
  7. Springboot使用EasyExcel(仅限自己收藏)
  8. 【深度分析】:阿里,腾讯面试题 SpringBoot整合Spring MVC
  9. 怎么用MindManager2019去做一个好的网络图
  10. 使用Eclipse创建Maven的JSP项目