题目大意

给定一个长为\(n\)的01串\(S\),每次你可以对一个串的三个连续位置做:\(011 \rightarrow 110\),\(110 \rightarrow 011\)的操作。

有\(q\)次询问,每次询问给出两个长度相等的子串,问是否能从一个串变到另一个串。

题解

首先,我们发现操作不改变\(1\)的个数。所以可以先用前缀和判断\(1\)的个数是否相等。

如果某个字符串不出现相邻的两个\(1\),那么容易得到你无法做任何有效的操作,就直接判断是否相等。这一步可以用hash或sa或sam实现。

否则我们又发现一个新的不变量,就是奇数位(是子串的奇数位)的\(1\)的个数和偶数位的\(1\)的个数都不改变!所以我们用前缀和算出两个串判断奇数位的\(1\),再判断是否相等

即可

提交

获得WA5的好成绩!

这给我们一个启示,就是简单的使用不变量无法得到正确的充要条件。

我们需要一个绝妙的想法。

把\(0\)看成小人,\(1\)看成空地。每次操作可以理解成把一个小人移动两个单位长度,且不改变小人之间的相对位置。

因此,从左到右每个小人所处位置的奇偶性是不变的。

设询问的字符串为\([l_1, r_1], [l_2, r_2]\),则先判断这两个子串的\(0\)的个数是否相等。如果相等,记它们为\(k\)。设从左往右第一个串的第\(i\)个\(0\)的在S的位置是\(a_i\),第二个串是\(b_i\)。

充要条件就是:对任意\(i\),\(a_i - l_1 \equiv b_i - l_2 (\mod 2)\)!

(至于条件的充分性,真的很好证的,就不写了)

我们把S中每个\(0\)连起来,然后如果这个\(0\)的下标为奇数,就在这个位置填上\(1\),否则填上\(0\),记这个新串是\(T_1\),把这个新串的\(01\)互换,形成\(T_2\)。

对\(T = T_1T_2\)建后缀数组或后缀自动机。问题变成了每次询问\(T\)的两个子串是否相等。

这是一个经典的问题。

#include <bits/stdc++.h>
#define debug(x) cerr << #x << " " << (x) << endl
using namespace std; const int N = 200005, K = 25; int n, q, len[N << 2], par[N << 2], last = 0, cnt = 0;
char str[N];
map<char, int> ch[N << 2];
void extend (char c) {
int p = last, np = ++cnt;
len[np] = len[p] + 1;
for (; ~p && !ch[p][c]; p = par[p]) ch[p][c] = np;
if (p < 0) par[np] = 0;
else {
int q = ch[p][c];
if (len[q] == len[p] + 1) par[np] = q;
else {
int nq = ++cnt;
ch[nq] = ch[q], len[nq] = len[p] + 1;
par[nq] = par[q], par[q] = par[np] = nq;
for (; ~p && ch[p][c] == q; p = par[p]) ch[p][c] = nq;
}
}
last = np;
} int tot = 0, id[N << 1], fa[N << 2][K], Log2[N << 2];
int zero[N << 1], pos[N]; int find_pos (int l, int r) {
int u = id[r];
for (int i = Log2[cnt]; i >= 0; i--) {
if (~fa[u][i] && len[fa[u][i]] > r - l) u = fa[u][i];
}
return u;
} int main () {
scanf("%d%s", &n, &str);
par[0] = -1, len[0] = 0;
for (int i = 0; i < n; i++) {
if (str[i] == '0') {
pos[tot] = i;
zero[tot++] = i & 1;
}
} for (int i = 0, j = 0; i < n; i++) {
if (str[i] == '0') {
zero[tot + j] = i & 1 ^ 1;
j++;
}
} for (int i = 0; i < (tot << 1); i++) extend(zero[i] + '0'), id[i] = last; Log2[1] = 0;
for (int i = 2; i <= cnt; i++) Log2[i] = Log2[i >> 1] + 1;
for (int i = 0; i <= cnt; i++) fa[i][0] = par[i];
for (int i = 1; i <= Log2[cnt]; i++) {
for (int j = 0; j <= cnt; j++) {
if (fa[j][i - 1] < 0) fa[j][i] = -1;
else fa[j][i] = fa[fa[j][i - 1]][i - 1];
}
} scanf("%d", &q);
for (int i = 0; i < q; i++) {
int l1, l2, len;
scanf("%d%d%d", &l1, &l2, &len), l1--, l2--; int L1 = lower_bound(pos, pos + tot, l1) - pos, R1 = lower_bound(pos, pos + tot, l1 + len) - pos;
int L2 = lower_bound(pos, pos + tot, l2) - pos, R2 = lower_bound(pos, pos + tot, l2 + len) - pos; bool flag = true;
if (R1 - L1 != R2 - L2) flag = false;
if (l1 & 1) L1 += tot, R1 += tot;
if (l2 & 1) L2 += tot, R2 += tot;
if (L1 < R1 && L2 < R2 && find_pos(L1, R1 - 1) != find_pos(L2, R2 - 1)) flag = false;
if (flag) puts("Yes");
else puts("No");
}
return 0;
}

CF1320 Div1 D.Reachable Strings 题解的更多相关文章

  1. 题解-Reachable Strings

    题解-Reachable Strings 前置知识: \(\texttt{Hash}\) Reachable Strings 给一个长度为 \(n\) 的 \(\texttt{01}\) 串 \(s\ ...

  2. CF1144A Diverse Strings 题解

    Content 我们定义一个字符串是合法的,当且仅当这个字符串是"连续排列"(按照字母表顺序排序).现在给出 \(n\) 个字符串 \(s_1,s_2,s_3,...,s_n\), ...

  3. POJ2406:Power Strings——题解

    http://poj.org/problem?id=2406 就是给一个串,求其循环节的个数. 稍微想一下就知道,KMP中nxt数组记录了所有可与前面匹配的位置. 那么如果我们的循环节长度为k,有n个 ...

  4. 洛谷 UVA10298 Power Strings 题解

    Analysis 结论:设字符串长度为n,最长相同前后缀的长度为kmp[i],如n%(n-kmp[n])=0,则答案为n/(n-kmp[n]),否则为1. 如果循环节多于一个,以前n-kmp[n]个为 ...

  5. POJ2406 Power Strings 题解 KMP算法

    题目链接:http://poj.org/problem?id=2406 题目大意:给你一个字符串 \(t\) ,\(t\) 可以表示为另一个小字符串循环了 \(K\) 了,求最大的循环次数 \(K\) ...

  6. CF544A Set of Strings 题解

    Content 有一个长为 \(n\) 的字符串 \(q\),试问能否将其划分为 \(k\) 个子串,使得每个子串的首字母都不相等,可以的话输出 \(\texttt{YES}\) 并输出任意一个方案, ...

  7. CF447B DZY Loves Strings 题解

    Content 有一个长度为 \(n\) 的仅含小写字母的字符串 \(s\) 以及 26 个英文小写字母的价值 \(W_\texttt{a},W_\texttt{b},...,W_\texttt{z} ...

  8. CF1547B Alphabetical Strings 题解

    Content 我们有一个空的字符串,第 \(i\) 次操作我们可以将字母表中第 \(i\) 个字母加入字符串的最前面或最后面.我们称一个长度为 \(n\) 的字符串是合法的,当且仅当这个字符串可以通 ...

  9. CF1506C Double-ended Strings 题解

    Content 有两个字符串 \(a,b\).我们每次操作可以将两个字符串中的一个字符串的最前面一个字符或这最后面一个字符删去(可以将某个字符串通过若干次操作变为空串).求需要多少次操作才能够使 \( ...

随机推荐

  1. 位图bitmap应用

    所有比特的编号方法是,从低字节的低位比特位开始,第一个bit为0,最后一个bit为 n-1. 比如说,现在有个数组是这样子的,int a[4],那么a[0]的比特位为0--31a[1]的比特位为32- ...

  2. JsonPath在接口自动化中的应用

    我理解jsonpath于json而言,就像是xpath在XML中的作用.用来确定json中某部分数据的语言.我更喜欢叫jsonpath表达式,因为这样好像是数学问题. 以前和小伙伴一起写接口自动化的时 ...

  3. 一:JavaWeb

    1.javaWeb技术体系 2.HTMl 超文本标记语言 (超文本的意思就是除了可以包含文字之外,还可以包含图片链接音乐视频等...) 2.1 HTML网页的组成  (结构:HTML 表现:CSS 行 ...

  4. 重要 | Spark分区并行度决定机制

    最近经常有小伙伴在本公众号留言,核心问题都比较类似,就是虽然接触Spark有一段时间了,但是搞不明白一个问题,为什么我从HDFS上加载不同的文件时,打印的分区数不一样,并且好像spark.defaul ...

  5. tomcat设置好环境变量,依然无法通过cmd startup命令启动

    Windows环境下JDK安装与环境变量配置详细的图文教程 https://www.cnblogs.com/liuhongfeng/p/4177568.html   Windows环境下maven 环 ...

  6. C/C++编程日记:逻辑井字棋(圈叉)(用空格初始化)

    问题描述: 3*3的棋盘中,只要一条线上出现三个一样的棋子就获胜(玩家或电脑):如果棋盘已经放满还未出现三个棋子一条线则打成平手. 具体细节: 初始化棋盘(用空格初始化)     //初始化棋盘 vo ...

  7. 免费|申请谷歌云服务器|msf安装

    apt-get install -y wget 参考链接 知乎-免费|申请谷歌云服务器 知乎-免费|申请谷歌云服务器 cnblogs-debian.ubuntu安装metasploit通用方法 谷歌云 ...

  8. 苹果电脑下载器Folx有没有自动下载功能

    苹果电脑下载器Folx提供了多项自动化任务功能,供用户更好地利用电脑的空闲时间,减少自己直接参与下载的时间,从而提升下载效率. 接下来,小编将重点介绍Folx自动化工作中的任务完成后的自动化工作.自动 ...

  9. JPA query between的多种方式(mongodb为例)

    背景 JPA+MongoDB查询,给定一段时间范围查询分页结果,要求时间范围包含. Page<Log> findByCtimeBetweenOrderByCtime( LocalDateT ...

  10. 早安打工人! 来把你的.NET程序模块化吧

    嗨朋友们,大家好! 还记得我是谁吗? 对了! 我就是 .NET 打工人 玩双截棍的熊猫 今天呐,我特别要向 写框架 的朋友们,想要写框架 ** 的朋友们,已经有框架** 的朋友问声好! 为什么呢?因为 ...