Codeforces 300C Beautiful Numbers 【组合数】+【逆元】

<题目链接>

题目大意:

给出a和b,如果一个数每一位都是a或b,那么我们称这个数为good,在good的基础上,如果这个数的每一位之和也是good,那么这个数是excellent。求长度为n的excellent数的个数mod(1e9+7)。

解题分析:

我们可以枚举a的个数m,所以b的个数为(n-m),然后判断这种情况是否可行,即,是否满足a*m+b*(n-m)为good number ,如果满足的话,则答案加上C(n,m)。因为n很大,并且在计算组合数的过程中,需要除以很大的数,所以需要求逆元,因为本题模数为1e9+7,为质数,所以可以用费马小定理求逆元。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define LL long long
using namespace std;
const LL MOD=1e9+7;
const LL MAXN=1e6+10;
 
LL a,b;
LL n;
LL fact[MAXN];//存i的阶乘
 
bool Sum_ok(LL x){   
    while(x){    //判断每一位是否只由a或b组成
        LL res=x%10;
        if(res!=a&&res!=b) return false;
        x=x/10;
    }
    return true;
}
LL pow(LL m,LL n){
    if(n==0) return 1;
    LL ans=1;
    while(n>0){
        if(n&1) ans=ans*m%MOD;
        m=m*m%MOD;
        n=n/2;
    }
    return ans;
}
int main(){
    scanf("%d %d %d",&a,&b,&n);
    fact[0]=1;
    for(LL i=1;i<=n;i++) fact[i]=fact[i-1]*i%MOD;//将fact数组初始化将阶乘的值存进数组,不要忘了取余
    LL ans=0;
    for(LL i=0;i<=n;i++){    //枚举a的个数
        if(is_gnum(a*i+b*(n-i))){    //判断枚举出的数是不是good number
            LL t1=pow(fact[i],MOD-2)%MOD;       //费马小定理求逆元,注意求逆元的格式,fact[i]、fact[n-i]均为除数 
            LL t2=pow(fact[n-i],MOD-2)%MOD;
            ans += fact[n]*t1%MOD*t2%MOD;//利用上面讲解中推导出的公式计算出答案,利用组合数公式,n!/(m!*(n-m)!) 
        }
    }
    printf("%lld\n",ans%MOD);
    return 0;
}

2018-10-09

猜你喜欢

转载自www.cnblogs.com/00isok/p/9762172.html