[R56E] 移位和
数据规模:,。
思路
循环右移 次后数字串恢复原样,因此 只取决于 ,问题转化为求循环右移 位后整数的数值。
记原数字串为 ,右移 位()得到 ,其数值为:
其中 是后缀 的数值, 是前缀 的数值。预处理三个数组(均对 取模):
- , 的幂;
- :前缀 的数值;
- :后缀 的数值。
于是 ,,代入得:
时 就是原数,即 。对每个 取 后 累加即可。运算中两个因子都小于 ,乘积不超过 ,64 位整数不会溢出。
复杂度:时间 ,空间 。
仓颉实现
import std.env.*
import std.convert.*
main(): Int64 {
let reader = getStdIn()
let first = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ p: String => Int64.parse(p) })
let n = first[0]
let m = first[1]
let xs = reader.readln().getOrThrow()
let MOD: Int64 = 1000000007
// pow10[i] = 10^i mod MOD, pre[i] = a[0..i-1] 的数值 mod MOD
let pow10 = Array<Int64>(n + 1, { _ => 0 })
let pre = Array<Int64>(n + 1, { _ => 0 })
pow10[0] = 1
var i: Int64 = 0
for (ch in xs) {
let d = Int64(ch) - 48
pre[i + 1] = (pre[i] * 10 + d) % MOD
pow10[i + 1] = pow10[i] * 10 % MOD
i = i + 1
}
// suf[k] = a[k..n-1] 的数值 mod MOD
let suf = Array<Int64>(n + 1, { _ => 0 })
var cur: Int64 = 0
var k = n - 1
while (k >= 0) {
let d = Int64(xs[k]) - 48
cur = (cur + d * pow10[n - 1 - k]) % MOD
suf[k] = cur
k = k - 1
}
var ans: Int64 = 0
let ls = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ p: String => Int64.parse(p) })
for (li in ls) {
let k = li % n
if (k == 0) {
ans = (ans + pre[n]) % MOD
} else {
// 右移 k 位:前 k 位是后缀 a[n-k..n-1],后 n-k 位是前缀 a[0..n-k-1]
ans = (ans + suf[n - k] * pow10[n - k] + pre[n - k]) % MOD
}
}
println(ans)
return 0
}