题面
首先可以想到 (5) 的倍数一定以 (5) 或 (0) 结尾,也就是我们选择的一段数字,只要保证结尾为 (0) 或 (5),前面数字是什么是无关答案,可以任选的。、
那么我们就先考虑在 a
这个串中如何统计答案,最后将 (k) 个串平起来的答案直接乘上去就好了。
对于字符串 a
,记最高位为第 (0) 位,最低位为第 (n-1) 位,根据乘法及加法原理,有:
[ans_a = 2^0 imes (a_0 == 5 || a_0 == 0) + 2^1 imes (a_1 == 5 || a_1 == 0) + cdots + 2^{n-1} imes (a_{n-1} == 5 || a_{n-1} == 0)
]
那么我们对于 (k) 个 a
,有这样的方案:
[ans_1 = ans_a imes (2^n)^0 \
ans_2 = ans_a imes (2^n)^1 \
ans_3 = ans_a imes (2^n)^2 \
cdots \
ans_k = ans_a imes (2^n)^{k-1}
]
对答案求一下和,发现其实就是等比数列求和,得到以下结果:
[ANS = ans_1 imes frac{2^{nk}-1}{2^n-1}
]
其中 (n) 为字符串长度。
于是这道题只剩下轻松愉快的快速幂和费马小定理求逆元了。
代码:
// 只要保证最后一位是 0 或 1,就能被 5 整除
// 所以答案是每一个 5 或非前导 0 之前的部分求方案
// s 不需要显式的建出来,每一个串对应多更新答案
// 前导 0 计算在结果中
# include <iostream>
# include <cstdio>
# include <string>
const long long MOD = 1e9+7;
long long QPow(long long x, long long y){
long long ans = 1, base = x%MOD;
while(y){
if(y & 1){
ans = (ans * base) % MOD;
}
base = (base * base) % MOD;
y >>= 1;
}
return ans;
}
long long Inv(long long x){
return QPow(x, MOD-2);
}
int main(){
std::string a; int k;
std::cin>>a>>k;
long long ans = 0;
for(int i = 0; i <= a.length()-1; i++){
if(a[i] == '0' || a[i] == '5'){
ans = (ans + QPow(2, i)) % MOD;
}
}
printf("%lld", (((ans * (QPow(2, 1ll*a.length()*k) - 1)) % MOD) * Inv(QPow(2, a.length())-1)) % MOD);
return 0;
}