CF300C Beautiful Numbers(排列组合/组合数取模)
链接:https://ac.nowcoder.com/acm/contest/21791/F
来源:牛客网
题目描述
给你两个数字 a a和 b b。一个数是由 a,b a,b两种数字构成,那么这个数是good;这个数的每一位加起来构成新的一个数,并且新数也是一个good数,那么称原数为excell。
求 n n位数中有多少个数是excell,输出 mod 109+7 mod 109+7 后的结果。 注意, n n位数不能有前导0。
输入描述:
第一行包含三个整数 a,b,n(1≤a<b≤9,1≤n≤106) a,b,n(1≤a<b≤9,1≤n≤106)。
输出描述:
输出一个整数。表示答案 mod 109+7 mod 109+7 后的结果。
示例1
输入
复制
1 3 3
输出
复制
1
说明
满足条件的三位数只有1个:111。
示例2
输入
复制
2 3 10
输出
复制
165
备注:
原题链接:https://codeforces.com/problemset/problem/300/C
注意到,当一个数是excell的时候,不管怎么排列这个数的每一位,它都是excell的。因此可以枚举含有的a的个数x,进而也可以得到b的个数y。如果x个a和y个b组成的数是excell的话就把答案加上\(C_n^x\)即可(相当于从n个位置选x个位置放a)。计算组合数直接套组合数取模的板子即可。
#include <bits/stdc++.h>
#define mod 1000000007
#define ll long long
#define LL long long
#define p 1000000007
using namespace std;
ll n, a, b;
bool judge(ll sum) {
while(sum) {
ll now = sum % 10;
sum /= 10;
if(now != a && now != b) {
return 0;
}
}
return 1;
}
const long long maxn = 2000005;
void extend_gcd(LL a,LL b,LL &x,LL &y){
if(b==0){
x=1,y=0;
return;
}
extend_gcd(b,a%b,y,x);
y-=a/b*x;
}
ll inv[maxn + 10];
ll f[maxn + 10];
void init(){//阶乘及其逆元打表
f[0]=1;
for(int i=1;i<=maxn;i++){
f[i]=f[i-1]*i%p;
}
LL x,y;
extend_gcd(f[maxn],p,x,y);//先求出f[N]的逆元,再循环求出f[1~N-1]的逆元
inv[maxn]=(x%p+p)%p;
for(int i=maxn-1;i>=1;i--){
inv[i]=inv[i+1]*(i+1)%p;
}
}
LL C(LL n,LL m){
if(n==m||m==0)return 1;
return (f[n]*inv[m]%p*inv[n-m]%p)%p;
}
int main() {
init();
cin >> a >> b >> n;
ll ans = 0;
for(ll i = 0; i <= n; i++) {
ll num = i * a + (n - i) * b;
if(judge(num)) {
ans = (ans + C(n, i)) % mod;
}
}
cout << ans;
return 0;
}