[R75B] 串移位


数据规模:1≤n≤2×1051 \le n \le 2 \times 10^5,0≤k≤10180 \le k \le 10^{18},ss 仅由大写英文字母组成。

思路

循环左移 kk 位后,新串 tt 的第 ii 个字符来自原串的 (i+k) mod n(i + k) \bmod n 位,即 t[i]=s[(i+k) mod n]t[i] = s[(i + k) \bmod n]。于是要统计的就是满足

s[i]=s[(i+k) mod n]s[i] = s[(i + k) \bmod n]

的下标 ii 的个数。

先把 kk 对 nn 取模,记 d=k mod nd = k \bmod n,因为移位数每达到 nn 就回到原串。取模后 0≤d<n0 \le d < n,所有下标运算都落在合法范围内,且 O(1)O(1) 取出 kk 的巨大值也不会溢出。

随后从 00 到 n−1n - 1 逐个枚举 ii,比较这两个字符是否相同并计数即可。特别地,当 d=0d = 0 时 tt 与 ss 完全相同,每个位置都贡献一次答案,这一点无需特判,循环本身就会得到 nn。

复杂度

时间 O(n)O(n),空间 O(n)O(n)(存放读入的字节串)。

仓颉实现

查看仓颉实现
import std.env.*
import std.convert.*

main() {
    let reader = getStdIn()
    let first = reader.readln().getOrThrow().split(" ", removeEmpty: true)
    let n = Int64.parse(first[0])
    let k = Int64.parse(first[1])
    let s = reader.readln().getOrThrow().toArray()
    let d = k % n
    var ans: Int64 = 0
    var i: Int64 = 0
    while (i < n) {
        if (s[i] == s[(i + d) % n]) {
            ans += 1
        }
        i += 1
    }
    println(ans)
}