1. 程式人生 > 其它 >CF300C Beautiful Numbers(排列組合/組合數取模)

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;
}