首页 > 其他分享 >G. Anya and the Mysterious String

G. Anya and the Mysterious String

时间:2023-10-14 15:14:18浏览次数:28  
标签:10 le String Mysterious query Anya 回文 ldots string

G. Anya and the Mysterious String

Anya received a string $s$ of length $n$ brought from Rome. The string $s$ consists of lowercase Latin letters and at first glance does not raise any suspicions. An instruction was attached to the string.

Start of the instruction.

A palindrome is a string that reads the same from left to right and right to left. For example, the strings "anna", "aboba", "level" are palindromes, while the strings "gorilla", "banan", "off" are not.

A substring $[l \ldots r]$ of string $s$ is a string $s_l s_{l+1} \ldots s_{r-1} s_r$. For example, the substring $[4 \ldots 6]$ of the string "generation" is the string "era".

A string is called beautiful if it does not contain a substring of length at least two that is a palindrome. For example, the strings "fox", "abcdef", and "yioy" are beautiful, while the strings "xyxx", "yikjkitrb" are not.

When an integer $x$ is added to the character $s_i$, it is replaced $x$ times with the next character in the alphabet, with "z" being replaced by "a".

When an integer $x$ is added to the substring $[l, r]$ of string $s$, it becomes the string $s_1 s_2 \ldots s_{l-1} (s_l + x) (s_{l+1} + x) \ldots (s_{r-1} + x) (s_r + x) s_{r+1} \ldots s_n$. For example, when the substring $[2, 4]$ of the string "abazaba" is added with the number $6$, the resulting string is "ahgfaba".

End of the instruction.

After reading the instruction, Anya resigned herself to the fact that she has to answer $m$ queries. The queries can be of two types:

  1. Add the number $x$ to the substring $[l \ldots r]$ of string $s$.
  2. Determine whether the substring $[l \ldots r]$ of string $s$ is beautiful.

Input

The first line contains an integer $t$ ($1 \le t \le 10^4$) - the number of test cases.

The descriptions of the test cases follow.

The first line of each test case contains two integers $n$ and $m$ ($1 \le n, m \le 2 \cdot 10^5$) - the length of the string $s$ and the number of queries.

The second line of each test case contains the string $s$ of length $n$, consisting of lowercase Latin letters.

The next $m$ lines contain the queries:

$1$ $l$ $r$ $x$ ($1 \le l \le r \le n$, $1 \le x \le 10^9$) - description of a query of the first type;
$2$ $l$ $r$ ($1 \le l \le r \le n$) - description of a query of the second type.
It is guaranteed that the sum of $n$ and the sum of $m$ over all test cases do not exceed $2 \cdot 10^5$.

Output

For each query of the second type, output "YES" if the substring $[l \ldots r]$ of string $s$ is beautiful, otherwise output "NO".

You can output "YES" and "NO" in any case (for example, the strings "yEs", "yes", "Yes", and "YES" will be recognized as positive answers).

Example

input

5
12 8
tedubcyyxopz
2 2 5
1 4 8 2
2 1 7
1 3 5 40
1 9 11 3
1 10 10 9
2 4 10
2 10 12
10 4
ubnxwwgzjt
2 4 10
2 10 10
1 6 10 8
2 7 7
11 3
hntcxfxyhtu
1 4 6 1
2 4 10
1 4 10 21
13 2
yxhlmzfhqctir
1 5 9 3
1 8 13 15
2 3
bp
1 1 2 15
1 1 2 18
1 2 2 1000000000

output

YES
NO
NO
YES
NO
YES
YES
YES

Note

In the first test case of the first test, the following happens:

  • tedubcyyxopz: the string edub is beautiful;
  • tedubcyyxopz $\to$ tedwdeaaxopz;
  • tedwdeaaxopz: the string tedwdea is not beautiful as it contains the palindrome edwde;
  • tedwdeaaxopz $\to$ terkreaaxopz;
  • terkreaaxopz $\to$ terkreaaarsz;
  • terkreaaarsz $\to$ terkreaaaasz;
  • terkreaaaasz: the string kreaaaa is not beautiful as it contains the palindrome aaaa;
  • terkreaaaasz: the string asz is beautiful.

 

解题思路

  关键的地方是要想到,如果对于一个长度为 $n > 1$ 的回文串 $s$,如果 $n$ 是偶数,那么其一定含有长度为 $2$ 的回文(子)串,即 $s_{\frac{n}{2}} \, s_{\frac{n}{2}+1}$。如果 $n$ 是奇数,那么其一定含有长度为 $3$ 的回文(子)串,即 $s_{\left\lceil \frac{n}{2} \right\rceil - 1} \, s_{\left\lceil \frac{n}{2} \right\rceil} \, s_{\left\lceil \frac{n}{2} \right\rceil + 1}$。

  因此要判断某个给定的区间是否含有回文串,只需关注这个区间内是否包含长度为 $2$ 的回文串或长度为 $3$ 的回文串即可。对此我们可以开两个平衡树 $\text{std::set}$ 来分别维护两种长度的回文串。对于原始的字符串,我们遍历所有长度为 $2$ 和 $3$ 的连续子串,如果是发现是长度为 $2$ 的回文串,则将其左端点(下标)存到 $\text{st}_1$,如果是长度为 $3$ 的回文串,则将其左端点存到 $\text{st}_2$。

  对于查询操作,假设询的区间是 $[l,r]$,那么只需在 $\text{st}_1$ 中二分出大于等于 $l$ 的最小下标,假设是 $x$,如果 $x < r$,则说明 $[l,r]$ 中存在回文串 $s_{x} \, s_{x+1}$。同时还需要在 $\text{st}_2$ 中二分出大于等于 $l$ 的最小下标,假设是 $x$,如果 $x < r-1$,则说明 $[l,r]$ 中存在回文串 $s_{x} \, s_{x+1}, \, s_{x+2}$。如果两种情况都不满足则说明 $[l,r]$ 中不存在回文串。

  对于修改操作,为了方便这里把字符 $a \sim z$ 映射成数字 $0 \sim 25$。可以发现对区间加 $[l,r]$ 上一个数后,区间内部的回文串并不会收到影响,即原本的回文串还是回文串,只不过数值改变了而已,也不会增加新的回文串。受影响的只有 $[l,r]$ 的边界点与区间外两侧的字符串。具体点来说就是 $s_{l-1} \, s_{l}$、$s_{l-2} \, s_{l-1} \, s_{l}$、$s_{l-1} \, s_{l+1}$,以及 $s_{r} \, s_{r+1}$、$s_{r} \, s_{r+1} \, s_{r+2}$、$s_{r-1} \, s_{r+1}$ 会受到影响。因此在修改前以及修改后都要在进行相应的维护(见代码)。由于我们需要进行区间加以及单点查询(某个下标是什么值),为了方便这里用树状数组来维护差分数组。

  AC 代码如下,时间复杂度为 $O((n+m) \log{n})$:

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

const int N = 2e5 + 10;

int n, m;
char s[N];
int tr[N];

int lowbit(int x) {
    return x & -x;
}

void add(int x, int c) {
    for (int i = x; i <= n + 1; i += lowbit(i)) {
        tr[i] = (tr[i] + c) % 26;
    }
}

int query(int x) {
    int ret = 0;
    for (int i = x; i; i -= lowbit(i)) {
        ret = (ret + tr[i]) % 26;
    }
    return ret;
}

void solve() {
    scanf("%d %d %s", &n, &m, s + 1);
    set<int> st1({n}), st2({n});    // 避免边界情况
    memset(tr, 0, n + 10 << 2);
    for (int i = 1; i <= n; i++) {
        add(i, s[i] - 'a');
        add(i + 1, 26 - (s[i] - 'a'));
        if (i + 1 <= n && s[i] == s[i + 1]) st1.insert(i);    // 长度为2的回文串,将其左端点存下来
        if (i + 2 <= n && s[i] == s[i + 2]) st2.insert(i);    // 长度为3的回文串,将其左端点存下来
    }
    while (m--) {
        int op, l, r, c;
        scanf("%d %d %d", &op, &l, &r);
        if (op == 1) {
            if (l - 1 >= 1 && query(l) == query(l - 1)) st1.erase(l - 1);
            if (l - 2 >= 1 && query(l) == query(l - 2)) st2.erase(l - 2);
            if (l + 1 <= r && l - 1 >= 1 && query(l + 1) == query(l - 1)) st2.erase(l - 1);
            if (r + 1 <= n && query(r) == query(r + 1)) st1.erase(r);
            if (r + 2 <= n && query(r) == query(r + 2)) st2.erase(r);
            if (r - 1 >= l && r + 1 <= n && query(r - 1) == query(r + 1)) st2.erase(r - 1);
            scanf("%d", &c);
            add(l, c % 26), add(r + 1, 26 - c % 26);
            if (l - 1 >= 1 && query(l) == query(l - 1)) st1.insert(l - 1);
            if (l - 2 >= 1 && query(l) == query(l - 2)) st2.insert(l - 2);
            if (l + 1 <= r && l - 1 >= 1 && query(l + 1) == query(l - 1)) st2.insert(l - 1);
            if (r + 1 <= n && query(r) == query(r + 1)) st1.insert(r);
            if (r + 2 <= n && query(r) == query(r + 2)) st2.insert(r);
            if (r - 1 >= l && r + 1 <= n && query(r - 1) == query(r + 1)) st2.insert(r - 1);
        }
        else {
            if (*st1.lower_bound(l) < r || *st2.lower_bound(l) < r - 1) printf("NO\n");    // 区间内存在长度为2或3的回文串
            else printf("YES\n");
        }
    }
}

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        solve();
    }
    
    return 0;
}

 

参考资料

  Codeforces Round 903 (Div. 3) Editorial:https://codeforces.com/blog/entry/121327

标签:10,le,String,Mysterious,query,Anya,回文,ldots,string
From: https://www.cnblogs.com/onlyblues/p/17764165.html

相关文章

  • string用法合集
    \(string\)用法:使用索引访问:strings="123123123";则\(s[0]=1,s[1]=2\cdots\)。可以直接用运算符比较:strings1="asd";strings2="dsa";returns1<s2;//按字典序来,结果应该返回的是true字符串排序:strings="1b3rdc871yvbv";so......
  • C. Decreasing String
    C.DecreasingStringRecallthatstring$a$islexicographicallysmallerthanstring$b$if$a$isaprefixof$b$(and$a\neb$),orthereexistsanindex$i$($1\lei\le\min(|a|,|b|)$)suchthat$a_i<b_i$,andforanyindex$j$($1\lej......
  • Codeforces Round 685 (Div. 2) B. Non-Substring Subsequence
    对于一个长为\(n\)的\(01\)字符串\(s\)有\(n\)个询问。第\(i\)个询问被\(l_i,r_i\)描述\(1\leql_i<r_i\leqn\)。对于每个询问,你需要确定\(s\)中是否存在一个子序列等同于子串\(s[l_i\cdotsr_i]\)。显然子序列可以和子串仅有一个字符不相同。于是\(s......
  • CF1886C Decreasing String 题解
    题面\(S_n\)由\(S_{n-1}\)去掉一个字母得到,\(S=S_1+S_2+...+S_n\)给定\(S_1\)求\(S\)的第\(N\)位solution我们先考虑怎样去字母能保持字典序最小显然,我们发现如果一个字母比前面那个字母小,那么我们就要删除前面那个字母也就是我们要删除一些字母,保持剩余的字母单调......
  • @NotBlank注解String字段会报错
    一、背景项目场景:这里说下@NotEmpty、@NotBlank、@NotNull的区别:它们所在的包:javax.validation.constraints.NotEmpty、javax.validation.constraints.NotBlank、javax.validation.constraints.NotNull1.@NotNull适用于基本数据类型(Integer,Long,Double,Date等等),当@NotNull......
  • CF938F Erasing Substrings 题解
    ErasingSubstrings一个神奇的想法是设\(f_{i,j}\)表示在位置\([1,i]\)中,我们删去了长度为\(2^k(k\inj)\)的一些串,所能得到的最小字典序。使用二分加哈希可以做到\(O(n^2\log^2n)\),无法承受。发现对于状态\(f_{i,j}\),它已经确定了\(i-j\)位的串,因为所有\(\inj\)......
  • 【OPCUA】UA_String转为QString
     字符串:UA_String typedef struct{ size_t length; UA_Byte* data;}UA_String; 生成UA_String的API有三个UA_STRING,UA_STRING_ALLOC,UA_STRING_STATICUA_STRING        - 包装现有数据(实际应用中,会有一些莫名其妙的问题)UA_STRING_ALLO......
  • QT--QString的arg方法
    在QT的QString中,arg方法类似于C中的printf中使用的格式输出符(只是有点类似)。在QT5的帮助文档中,可以看出以下几点:使用arg(str1,str2,str3)这种方法进行替换。使用arg(str1).arg(str2).arg(str3)这种方法进行替换。​使用arg(int, int, int)这种方式进行替换。解释......
  • Python word'str'(字符串前缀string prefix)的种类
    Python字符串前缀(Stringprefix) r'string'r'',用法是不会对后方字符串中的转义符进行转义,如: str=r'\n'print(str)#会直接输出\n,并不会输出换行 f'string'f'',用法是对字符进行格式化就和str.format()一样,会对{}进行格式化,如: str=f'你好,{}'......
  • 2023.10.10 js.Array和js.String
    1定义数组21.vararr=newArray{1,2,3,4...};32.vararr=[1,2,3,4];4访问5arr[索引]=值67同一数组的类型可变,长度可变。89Array中的属性和方法10arr.length//获取数组长度11forEach()遍历数组中的每个有值的元素,并调用一次传入的函数12arr......