CF 300C - Beautiful Numbers (数论)

(广东工业大学 ACM寒假集训 专题四 C)
题目链接:CF 300C - Beautiful Numbers
洛谷链接:CF 300C - Beautiful Numbers
更好的阅读体验请到这里

题目描述(洛谷翻译):
题意翻译
Vitaly有一些奇怪的癖好,比如他特别爱两个小于10的数字a和b。Vitaly定义十进制表示下每一位都是a或b的数为“好数”,一个每一位数加起来为“好数”的“好数”被称为“极好的数”。

举个栗子=w=,如果偏爱数字为1和3,那么1212不是“好数”,13和311是“好数”,111是“极好的数”。

现在Vitaly想知道,长度为n(长度不包括前导0)的“极好的数”有多少个。对1e9+7取模。
在这里插入图片描述

读题

1、有两个数字a,b。
2、“好数”是只由a,b构成的长度为n的数。
3、"好数"中每一位之和也是"好数"的数,叫“极好的数”。
4、题目要我们找“极好的数”(以下简称极好数)。
5、答案取模1e9+7,为质数。

总体思路:
因为我们找的极好数来自好数,那么我们只要枚举长度为n的所有好数,判断是不是每一位之和为好数,是的话说明是极好数,结果累加起来就可以了。
如何枚举:
一个一个数枚举是不可能的,有1000000位数呢…但是仔细想一下,数的长度是固定为n的,且只有a,b,那么我们是不是就可以枚举a的数量i,那么b的数量一定是n-i,这时候这么多个a和b组成的数就相当于i个a去放n个空位(组合数),所以就是C(n,i)(n在下,i在上)。
如何求这个组合数:
简单,运用组合数公式:在这里插入图片描述
答案怎么求,如何求mod:
我们不是求出来之后才取模。

分析:
每个答案是一个组合数,但是组合数是一个分式,因为太大了,我们不能求出阶乘后再除下面的阶乘,我们要除数取模。
(a/b)mod p ≠(a mod p/ b mod p)mod p
这里我们要用费马小定理求逆元:
n ! i ! ( n − i ) ! \frac{n!}{i!(n-i)!} i!(ni)!n!
由公式可知,我们要求 i!(n-i)!的逆元,让他变成乘法来取模。因为p是质数,所以可以用费马小定理,用快速幂求逆元。

#include<iostream>//组合数,费马小定理,快速幂,逆元
using namespace std;
const long long mod=1e9+7;
long long fact[1000005];
long long a,b,n,ans=0;
bool good(long long x){
    while(x){
        long long tmp=x%10;
        if(tmp!=a && tmp!=b)return false;
        x/=10;
    }
    return true;
}
long long fastpow(long long f,long long p){
    if(p==0)return 1;
    long long res=1;
    while(p){
        if(p&1)res=res*f%mod;
        f=f*f%mod;//反正每次模就行,不要让他超longlong
        p>>=1;
    }
    return res;
}
int main()
{
    cin>>a>>b>>n;
    fact[0]=1;
    for(int i=1;i<=n;i++)fact[i]=fact[i-1]*i%mod;//打表,每次取模
    for(int i=0;i<=n;i++){
        if(good(a*i+b*(n-i))){
            long long tmp1=fastpow(fact[i],mod-2)%mod;//费马小定理求逆元
            long long tmp2=fastpow(fact[n-i],mod-2)%mod;//求完就取模
            ans+=fact[n]*tmp1%mod*tmp2%mod;//因为n!已经取过模了,所以是后面两个取
        }
    }
    printf("%lld\n",ans%mod);
}

好像也讲的不清楚…

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值