[洛谷 1313]計算係數---二項式定理+快速冪+逆元(費馬小定理)
題目描述
給定一個多項式(by+ax)^k,請求出多項式展開後x^n*y^m 項的係數。
輸入輸出格式
輸入格式:
輸入檔名為factor.in。
共一行,包含5 個整數,分別為 a ,b ,k ,n ,m,每兩個整數之間用一個空格隔開。
輸出格式:
輸出共1 行,包含一個整數,表示所求的係數,這個係數可能很大,輸出對10007 取模後的結果。
輸入輸出樣例
輸入樣例#1:
1 1 3 1 2
輸出樣例#1:
3
說明
【資料範圍】
對於30% 的資料,有 0 ≤k ≤10 ;
對於50% 的資料,有 a = 1,b = 1;
對於100%的資料,有 0 ≤k ≤1,000,0≤n, m ≤k ,且n + m = k ,0 ≤a ,b ≤1,000,000。
noip2011提高組day2第1題
分析
神奇的數學題,直接提示了二項式定理( 其實就是說楊輝三角與二項式的係數相同,與C(n,m)相同 )
由定理直接可以得出第x^n*y^m 項為:C(k,m)* (a*x)^n* (b*y)^m
化簡可得其係數為: C(k,m) * a^n * b^m
PS:由於二項式/楊輝三角性質可知 n+m=k 則 C(k,m)=C(k,k-n)=C(k,n)
對於後二者,直接用快速冪(如果不知道,那麼88,走錯片場了)來求就行了.
對於C(k,m),有兩種方法,其一是形如楊輝三角的遞推(C(k,m)=C(k-1,m-1)+C(k-1,m)).其二是考慮分解質因數+高精度
對此僅給出逆元的解法(快速冪求逆元)
1.逆元定義:對於正整數a和m,如果有 a*x≡1(mod m) { 即 a*x%m=1%m },那麼把這個同餘方程中的最小正整數解叫做a模m的逆元。
2.費馬小定理:假如p是質數,且gcd(a,p)=1,那麼 a(p-1)≡1(mod p),即:假如a是整數,p是質數,且a,p互質(即兩者只有一個公約數1),那麼a的(p-1)次方除以p的餘數恆等於1
3.對於除法取模來說 (a/b)%m=((a%mo)/(b%mo))%mo 是不存在的但對於+ - * ^ 來說成立,所以說可以考慮將 (a/b)%m轉化為 a*(b^-1)%mo . 當然,直接轉換是不存在的,於是藉助逆元進行轉化
由於mo=10007為質數,與b=(m-k)!* m! 互質,所以,由費馬小定理可得: b^(mo-1)=1(mod mo) 又因為 b^-1*b=1
so b^(mo-1)=b^-1*b –> b^-1=b^(mo-2)
於是 (令 b=(m-k)!* m!)
C(k,m)%mo=( k!/b) %mo=( k! b^-1 )%mo=( k! *b^(mo-2))%mo=((k!%mo)
其中b^(mo-2)可用快速冪解決
程式碼
數論程式碼一般都十分醜陋
貌似不用開long long的樣子
#include <cstdio>
#include <cstdlib>
#define open(s) freopen(s".in","r",stdin); freopen(s".out","w",stdout);
#define close fclose(stdin); fclose(stdout);
using namespace std;
int mo=10007;
int jc[1005];
inline int read()
{
int k=1;
int sum=0;
char c=getchar();
for(;'0'>c || c>'9' ;c=getchar())
if(c=='-') k=-1;
for(;'0'<=c && c<='9';c=getchar())
sum=sum*10+c-'0';
return sum*k;
}
inline void write(int x)
{
if(x<0) { putchar('-'); x*=-1; }
if(x>9) write(x/10);
putchar(x%10+'0');
}
inline int power(int x,int t)//快速冪 x^t
{
if(t==1) return x;
int s=power(x,t>>1);
s=s*s%mo;
return t&1?s*x%mo:s;
}
int main()
{
open("1313");
int a=read(),b=read(),k=read(),n=read(),m=read();
jc[0]=1;
for(int i=1;i<=k;++i) jc[i]=(jc[i-1]*i)%mo;//預處理階乘
n%=mo; m%=mo;//由於n,m,a,b都可能比mo大,所以先取模
a%=mo; b%=mo;
int ans=1;
//三部分
ans=(jc[k]*power((jc[k-n]*jc[n])%mo,mo-2))%mo;
ans=(ans*power(a,n))%mo;
ans=(ans*power(b,m))%mo;
write(ans);
close;
return 0;
}