CodeForces - 300C Beautiful Numbers

本文探讨了一个数学问题,即计算在给定长度n下,由特定两位数字组成的数中,其数字之和同样由这两位数字构成的数量。文章通过分析示例,提出了解决方案,利用组合数和卢卡斯定理进行高效计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题面

Vitaly is a very weird man. He’s got two favorite digits a and b. Vitaly calls a positive integer good, if the decimal representation of this integer only contains digits a and b. Vitaly calls a good number excellent, if the sum of its digits is a good number.

For example, let’s say that Vitaly’s favourite digits are 1 and 3, then number 12isn’t good and numbers 13 or 311 are. Also, number 111 is excellent and number 11isn’t.

Now Vitaly is wondering, how many excellent numbers of length exactly n are there. As this number can be rather large, he asks you to count the remainder after dividing it by 1000000007 (10910^9109+ 7).

A number’s length is the number of digits in its decimal representation without leading zeroes.

Input

The first line contains three integers: a, b, n (1 ≤ a < b ≤ 9, 1 ≤ n ≤ 10610^6106).

Output

Print a single integer — the answer to the problem modulo 1000000007 (109 + 7).

Examples

Input

1 3 3

Output

1

Input

2 3 10

Output

165

题目大意

给定两个数a,b,与一个长度n,问你在长度n的限制下,用a,b组成一个数,然后问你这个数n位上的和的n位都是a或者b的数的个数是多少。

第一个样例中,用1,3组成一个长度为3的数字,全部有:

111,113,131,133,311,313,331,333,而他们的各位上的和分别是:

3,4,5,7,4,7,7,9

很显然,和的各位上(这里只有一位,所以和为1或3就行)依旧为1或者3只有一个111。所以输出1。

最后的结果mod 1e9+7。

题目分析

这道题枚举是不可能枚举的了,这辈子都不可能枚举的了。n的取值高达1e6,那是一个多长的数字……

再回看第一个样例,我们留意到,1和3的位置并不影响它们的和。所以我们只需要留意一下1和3的个数,看它们的和是否是符合条件的就行。符合的话我们再用组合数来计算一下数位上1和3有那么多个的数有多少个。

再拿第一个样例举例。我们知道:

1的个数3的个数
303
215
127
039

符合条件的只有3个1,运用高中的组合知识,3位上各放一个1的个数有C33C^3_3C33个,也就是1个输出就行了。

可是在本题当中,由于最后的个数巨大,组合数也是有可能巨大,所以我们要进行取模。组合数取模自然是要用到卢卡斯定理啦。直接上模板。先预处理,再写求逆元的函数,用费马小定理(扩展欧几里得也行,1e+7是个质数)用费马小定理自然是用到了快速幂。都是套模板。

代码

#include <cstdio>
using namespace std;
typedef long long ll;
const int mod = 1e9+7;
const int maxm = 1e7;
int a, b, n;
ll fact[maxm];

bool is(int m){
  bool r = true;
  while(m){
    if(m % 10 != a && m % 10 != b)
      return r = false;
    m /= 10;
  }
  return r;
}
void init(int m){
  fact[0] = 1;
  for(int i = 1; i <= m; i++){
    fact[i] = fact[i - 1] * i % mod;
  }
}

ll pow_mod(ll a, ll m){
  ll base = a;
  ll ans = 1;
  while(m){
    ans = (m & 1)? ans * base % mod: ans;
    base = base * base % mod;
    m >>= 1;
  }
  return ans;
}

ll inv(ll m){
  return pow_mod(m, mod - 2);
}

ll C(ll n, ll m){
  if(n < m) return 0;
  else {
    return fact[n] * inv(((fact[m] % mod) * (fact[n - m] % mod)) % mod) % mod;
  }
}

ll lucas(ll n, ll m){
  return m?(C(n % mod, m % mod) * lucas(n / mod, m / mod) % mod) :1;
}
int main(int argc, char const *argv[]) {
  while(~scanf("%d%d%d", &a, &b, &n)){
    int ans = 0;
    init(n);
    for(int i = 0; i <= n; i++){
      int sum = i * a + (n - i) * b;
      if(is(sum)){
        ans = (ans + lucas(n, i)) % mod;
      }
    }
    printf("%d\n", ans % mod);
  }
  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值