您的位置:首页 > 其它

CodeForces 300C Beautiful Numbers (乘法逆元+快速幂(含乘法逆元的讲解))

2014-08-06 23:45 162 查看

C. Beautiful Numbers

time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
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 digitsa andb. 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 12 isn't good and numbers 13 or 311 are. Also, number 111 is excellent and number11 isn'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(109 + 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 ≤ 106).

Output

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

Sample test(s)

Input

1 3 3

Output

1

Input

2 3 10

Output

165

题意:某人喜欢两个数字a和b,他把各位上完全有这两个数字组成的数字叫做good number(当然也可以只有a或只有b组成),要是组成的数字的各位加起来的和也是good number,那么这个由a,b组成的good number就是excellent,输入三个数a,b,n,分别代表喜欢的数a,b和要组成的数的位数,求最多有多少个符合题意的excellent?

比如第一个样例只有111符合题意,所以答案是1.

由于现在网上好多的博客讲解只有几句话。。。真心看不懂,所以经过各种途径每搞懂一道题我都会尽最大可能写详细点的题解,不然别人看着也是头痛,正好也当复习一下知识。。。

题解:

比赛时遇到这道题,果断悲剧了,由于数论太渣WA了无数次。。。

这道题主要用的就是乘法逆元加上一个快速幂的技巧的方法,估计有人会和我一样看到这里就愣住了。。。什么是乘法逆元???

这里我就先讲一下乘法逆元:

乘法逆元的定义很简单:若对于数字A,C存在X,使得A * X = 1(mod C),那么称X为 A 对 C 的乘法逆元。

那么乘法逆元的作用呢?比如:(求下面等式中的ans)

F / A mod C = ans;

如果存在A * X = 1 (mod C);

那么两边乘起来就会有:F * X = ans(mod C);

这样除法就转化为乘法了。。。

在上述公式A * X = 1 (mod C);中当A与C互质时,A关于模C的乘法逆元X有唯一解,如果不互质,则无解。如果C是是质数那么在1到(C-1)之间的任意数都与C互质。

这样在要求上述的ans只要求出乘法逆元X就可以了。

那么怎么求乘法逆元网上有好多些介绍但比较杂,由于是刚刚自学下面说的可能不太完整,欢迎过路的大神门多多的提意见。

乘法逆元的求法:

这里设inv(a)为a的乘法逆元。

根据这个题来说,因为数字的位数len已经确定了,又因为数字都是由输入的a,b组成的,那么就可以对 a 的个数进行枚举,这样枚举出的数字都是good number,如果设a的个数是 i ,那么 b 的个数就是 len-i ,那么该数各位数字的和就是sum = a * i + b * ( len - i ) 然后在判断sum是不是good number就知道有 i 个a 和 len-i 个 b 组成的good
number数是不是excellent了,接下来貌似就是求简单的组合数C(len, i)%MOD,但是看看数据,10^6这可不是简单的组合数公式就能求出的,接下来就该用到前面说的知识了,利用前面说的乘法逆元的作用可得:因为 c ( len , i ) % MOD = ( len ! / ( i ! * ( len - i ) ! ) ) % MOD,类似上面的做法可以得出:c ( len , i ) % MOD = len ! * inv ( i ! * ( len-i ) ! )% MOD,接下来只要求出
inv ( i ! * ( len - i ) ! ) 即( i!*(len-i)! )的乘法逆元就可以了。

这里用欧拉函数结合快速幂的技巧来求:

gcd(a, p)=1, t = Eula(p)

则a的逆元是 inv(a) = a^(t-1)

Eula(p) 是p的欧拉函数。欧拉函数就是在(1, n)的区间里与p互素的数的个数。

那么如何求Eula(p)?

1,p是素数,Eula(p) = p-1,根据定义可知。

2,p不是素数。Eula(p)=p-p/x (x是p的所有素因子, 对于相同因子只使用1次)

快速幂在程序中会有体现。

这是你会发现题目中为什么会给一个MOD=10^9+7了。。。一位它是质数,哈哈

也就是说上述

inv(i!*(len-i)!)%MOD

=( i!*(len-i)! )^(MOD-2)%MOD 注:( Eula(MOD) = MOD-1 )

=(i!)^(MOD-2)%p*( (len-i)! )^(MOD-2)%MOD

哈哈,现在上面的题目就能解决了,下面是代码和注释:


题目连接地址:http://codeforces.com/problemset/problem/300/C

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define LL long long
#define ERR "***here***"
using namespace std;
const LL MOD=1e9+7;//定义10^9+7
const LL MAXN=1e6+10;

LL a,b;//输入的a,b
LL len;//数字的长度len
LL fact[MAXN];//用来存1到len的阶乘

bool is_gnum(LL x){//判断函数,用来判断i*a+(len-i)*b是不是good number</span>
while(x){
LL p=x%10;
if(p!=a&&p!=b) return false;
x=x/10;
}
return true;
}

LL cal(LL m,LL n){//利用快速幂计算m^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,&len);
fact[0]=1;
for(LL i=1;i<=len;i++) fact[i]=fact[i-1]*i%MOD;//将fact数组初始化将阶乘的值存进数组,不要忘了取余
LL ans=0;//储存答案
for(LL i=0;i<=len;i++){
if(is_gnum(a*i+b*(len-i))){//判断i*a+(len-i)*b是不是good number</span>
LL t1=cal(fact[i],MOD-2)%MOD;
LL t2=cal(fact[len-i],MOD-2)%MOD;
ans += fact[len]*t1%MOD*t2%MOD;//利用上面讲解中推导出的公式计算出答案
}
}
printf("%lld\n",ans%MOD);//将答案输出,不要忘了取余
return 0;
}



                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: