藍橋練習系統 歷屆試題 公式求值
阿新 • • 發佈:2019-02-15
20、 歷屆試題 公式求值
問題描述
輸入n, m, k,輸出下面公式的值。
其中C_n^m是組合數,表示在n個人的集合中選出m個人組成一個集合的方案數。組合數的計算公式如下。
輸入格式
輸入的第一行包含一個整數n;第二行包含一個整數m,第三行包含一個整數k。
輸出格式
計算上面公式的值,由於答案非常大,請輸出這個值除以999101的餘數。
樣例輸入
3
1
3
樣例輸出
162
樣例輸入
20
10
10
樣例輸出
359316
資料規模和約定
對於10%的資料,n≤10,k≤3;
對於20%的資料,n≤20,k≤3;
對於30%的資料,n≤1000,k≤5;
對於40%的資料,n≤10^7,k≤10;
對於60%的資料,n≤10^15,k ≤100;
對於70%的資料,n≤10^100,k≤200;
對於80%的資料,n≤10^500,k ≤500;
對於100%的資料,n在十進位制下不超過1000位,即1≤n<10^1000,1≤k≤1000,同時0≤m≤n,k≤n。
提示
999101是一個質數;
當n位數比較多時,絕大多數情況下答案都是0,但評測的時候會選取一些答案不是0的資料;
問題描述
輸入n, m, k,輸出下面公式的值。
其中C_n^m是組合數,表示在n個人的集合中選出m個人組成一個集合的方案數。組合數的計算公式如下。
輸入格式
輸入的第一行包含一個整數n;第二行包含一個整數m,第三行包含一個整數k。
輸出格式
計算上面公式的值,由於答案非常大,請輸出這個值除以999101的餘數。
樣例輸入
3
1
3
樣例輸出
162
樣例輸入
20
10
10
樣例輸出
359316
資料規模和約定
對於10%的資料,n≤10,k≤3;
對於20%的資料,n≤20,k≤3;
對於30%的資料,n≤1000,k≤5;
對於40%的資料,n≤10^7,k≤10;
對於60%的資料,n≤10^15,k ≤100;
對於70%的資料,n≤10^100,k≤200;
對於80%的資料,n≤10^500,k ≤500;
對於100%的資料,n在十進位制下不超過1000位,即1≤n<10^1000,1≤k≤1000,同時0≤m≤n,k≤n。
提示
999101是一個質數;
當n位數比較多時,絕大多數情況下答案都是0,但評測的時候會選取一些答案不是0的資料;
用到的知識 lucas定理 尤拉定理 或費馬小定理 快速冪 數學組合公式推導
lucas定理 求C(n,m)%p
數論Lucas定理:是用來求 c(n,m) mod p的值,p是素數(從n取m組合,模上p)
描述為:
Lucas(n,m,p)=cm(n%p,m%p)* Lucas(n/p,m/p,p)
Lucas(x,0,p)=1;
而
cm(a,b)=a! * (b!*(a-b)!)^(p-2) mod p
也= (a!/(a-b)!) * (b!)^(p-2)) mod p
這裡,其實就是直接求 (a!/(a-b)!) / (b!) mod p
由於 (a/b) mod p = a * b^(p-2) mod p
費馬小定理 a^(p-1) mod p=1 (mod p)
import java.math.BigInteger; import java.util.Scanner; public class L_20END { /*** * @author 林梵 */ public static BigInteger lucas(BigInteger n,BigInteger m,BigInteger p){ if(m.equals(BigInteger.ZERO)) return BigInteger.ONE; return BigInteger.valueOf(f(n.mod(p).longValue(),m.mod(p).longValue())).multiply(lucas(n.divide(p),m.divide(p),p)).mod(p); } public static long f(long n,long m){ if(m>n) return 1; if(n==m|| m==0) return 1; if(m>n-m) m=n-m; long tmpi=1,tmpn=1,s1=1,s2=1,ans=1; for (int i = 1; i<=m; i++) { tmpi=i; tmpn=n-i+1; s1=s1*tmpi%999101; s2=s2*tmpn%999101; } ans = s2*pow1(s1,999099)%999101; return ans%999101; } public static long pow1(long x,long n) { if(x==1) return 1; if (n==0) return 1; else { while ((n & 1)==0) { n>>=1; x=(x *x)%999101; } } long result = x%999101; n>>=1; while (n!=0) { x=(x *x)%999101;; if ((n & 1)!=0) result =result*x%999101; n>>=1; } return result; } public static void main(String[] args) { Scanner sc = new Scanner(System.in); BigInteger n = new BigInteger(sc.nextLine()); BigInteger m = new BigInteger(sc.nextLine()); int k = Integer.parseInt(sc.nextLine()); long start = System.currentTimeMillis(); BigInteger md = new BigInteger("999101"); long Cnm=lucas(n, m,md).longValue()%999101; long sum = 0; if(Cnm!=0){ int[][] a = new int[k][k]; int h = 1; for (int i = 0; i < k; i++) { for (int j = 0; j < k; j++) { if (j >= h) a[i][j] =0; else { if (j == 0 || j == h - 1) a[i][j] = 1; else { a[i][j] = (a[i - 1][j - 1]*(h - j)+a[i - 1][j])%999101; } } } h++; } long m1 = 1,n1 =1; long x=n.subtract(new BigInteger(k+"")).mod(md.subtract(BigInteger.ONE)).longValue(); long n3 = pow1(2,x); for (int i = k - 1; i >= 0; i--) { n1=n3*pow1(2,i)%999101; m1 = m1*(n.subtract(new BigInteger((k - 1 - i) + "")).mod(md).longValue())%999101; sum = (sum+m1*a[k - 1][i]*n1)%999101; } sum = sum*Cnm%999101; } System.out.println(sum); long end = System.currentTimeMillis(); System.out.println(end - start); } }