[CodeForces][数学][组合][快速幂] CF327C Magic Five
题面
首先可以想到 \(5\) 的倍数一定以 \(5\) 或 \(0\) 结尾,也就是我们选择的一段数字,只要保证结尾为 \(0\) 或 \(5\),前面数字是什么是无关答案,可以任选的。、
那么我们就先考虑在 a
这个串中如何统计答案,最后将 \(k\) 个串平起来的答案直接乘上去就好了。
对于字符串 a
,记最高位为第 \(0\) 位,最低位为第 \(n-1\) 位,根据乘法及加法原理,有:
\[ans_a = 2^0 \times (a_0 == 5 || a_0 == 0) + 2^1 \times (a_1 == 5 || a_1 == 0) + \cdots + 2^{n-1} \times (a_{n-1} == 5 || a_{n-1} == 0)
\]
那么我们对于 \(k\) 个 a
,有这样的方案:
\[ans_1 = ans_a \ \times\ (2^n)^0 \\
ans_2 = ans_a \ \times\ (2^n)^1 \\
ans_3 = ans_a \ \times\ (2^n)^2 \\
\cdots \\
ans_k = ans_a \ \times\ (2^n)^{k-1}
\]
对答案求一下和,发现其实就是等比数列求和,得到以下结果:
\[ANS = ans_1 \ \times\ \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;
}