NOIP 2011 计算系数

题目描述

求 (ax+by)^k 的展开中 x^n*y^m 项的系数。由于系数可能很大,只要求输出除以 10007 的余数。 

输入

一行共五个整数,分别为 a,b,k,n,m 

输出

一个整数,为该项系数除以10007的余数。 

样例输入

1 1 3 1 2

样例输出

数据范围:

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 }
原文地址:https://www.cnblogs.com/cutepota/p/12067016.html