题目描述
求 (ax+by)^k 的展开中 x^n*y^m 项的系数。由于系数可能很大,只要求输出除以 10007 的余数。
输入
一行共五个整数,分别为 a,b,k,n,m
输出
一个整数,为该项系数除以10007的余数。
样例输入
1 1 3 1 2
样例输出
3
数据范围:
30% 0<=k<=10,
50% a=1,b=1
100% 0<=k<=1000, 0<=n,m<=k 且 n+m=k, 0<=a,b<=100,000
Sol1:假设a=b=1,则(x+y)^k的展开项的系数,是一个杨辉三角,先计算杨辉三角前k行的值,ans=x[k][n],再用ans*a^n*b^m即可,注意取模,以及在计算杨辉三角的时候二维数组的坐标从(0,0)开始。
1 #include<bits/stdc++.h> 2 #define s 1100 3 using namespace std; 4 int x[s][s]; 5 main() 6 { 7 int a,b,k,n,m; 8 x[0][0]=1; 9 scanf("%d%d%d%d%d",&a,&b,&k,&n,&m); 10 a%=10007; 11 b%=10007; 12 for(int i=1;i<=k;i++)//计算前k行的杨辉三角 13 for(int j=0;j<=i;j++) 14 x[i][j]=(x[i-1][j]+x[i-1][j-1])%10007;} 15 16 int ans=x[k][n]; 17 for(int i=1;i<=n;i++) ans=ans*a%10007;//ans乘上a^n取模 18 for(int i=1;i<=m;i++) ans=ans*b%10007;//ans再乘上b^m取模 19 printf("%d",ans); 20 return 0; 21 }
sol2:求组合数时,可直接算组合数C(k,n)=分子/分母,然后在取模的时候,求出分母这个数值针对p的逆元即可。
当然也可以在计算过程中,算出分母中1到m每个数字针对p的逆元。转化成k*(k-1)*(k-2)*......*(k-n-1) * 1的逆元 * 2的逆元 * 3的逆元*.....m的逆元。
求逆元的几种方法
1:单个数字可以用扩欧来求解
2:1--N之间所有数字,可以递推求解
3:用欧拉定理,直接找出逆元,代码如下。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int p=10007; 4 long long ksm(long long a,long long b)//快速幂求阶乘 5 { 6 if(b==0)return 1; 7 if(b%2==0)return ksm(a,b>>1)*ksm(a,b>>1)%p; 8 else return a*ksm(a,b>>1)*ksm(a,b>>1)%p; 9 } 10 int main() 11 { 12 int a,b,k,m,n; 13 cin>>a>>b>>k>>n>>m; 14 int c=1,d=1; 15 for(int i=1;i<=n;i++)//求出分母 16 c=c*i%p; 17 for(int i=k-n+1;i<=k;i++)//求出分子 18 d=d*i%p; 19 d=d*ksm(c,p-2)%p;//分子*分母的逆元,分母的逆元为c^(p-2),因为要使cx%p=1,根据欧拉定理有c^(p-1)%p=1,所以x为c^(p-2) 20 d=d*ksm(a,n)*ksm(b,m)%p;//再乘上a^n和b^m 21 cout<<d; 22 }