Hesablama mərtəbəli işarəsiz uzun tam ədədlərdən (unsigned long long) istifadə ediləcək. Aydındır ki,
Dəyişən -ə dəyərini verək, sonra -dən -ə qədər üçün -i {n - i + 1 \over i} ilə artıracağıq. Hər dəfə ilə bölünmə tam şəkildə olacaq, lakin çoxalma zamanı daşıma baş verə bilər. Qoy d = ÜOD(res, i). Bu hal
ondan
ilə yenidən yazırıq.
Bu üsulda çoxalmanın artıq daşıması baş verməyəcək (cavab mərtəbəli işarəsiz uzun tam ədəddir). Əvvəlcə (n - i + 1 ) / (i / d) bölünməsini, sonra çoxalmaları tamamlanmalıdır.
C_n^k hesablamaq üçün iterasiya edəcək. Bəs C_{2000000000}^{1999999999} hesablamalısınızsa nə etməli? Cavab 2^{64} ilə məhdudlaşmayacaq, buna görə belə giriş məlumatı mümkündür. C_n^k = C_n^{n-k} olduğundan, n-k < k olduqda k = n-k qoymaq lazımdır.
Misal
Nu aşağıdakı misalı nəzərdən keçirək:
Qoy res = 15, və çoxalma res \cdot {4 \over 3} = 15 * {4 \over 3} başa qalıb. Hesablayırıq d = ÜOD(15, 3) = 3. Buna görə 15 \cdot {4 \over 3} = (15 / 3) \cdot {4 \over 3 / 3} = 5 \cdot {4 \over 1} = 20.
Alqoritmin icrası
gcd funksiyası və ədədlərinin ən böyük ortaq bölənini hesablayır.
unsigned long long gcd(unsigned long long a, unsigned long long b)
{
return (!b) ? a : gcd(b,a % b);
}Cnk funksiyası binomial əmsalın C_n^k dəyərini hesablayır.
unsigned long long Cnk(unsigned long long n, unsigned long long k)
{
unsigned long long CnkRes = 1, t, i;
if (k > n - k) k = n - k;
for(i = 1; i <= k; i++)
{
t = gcd(CnkRes, i);
CnkRes = (CnkRes / t) * ((n - i + 1) / (i / t));
}
return CnkRes;
}Proqramın əsas hissəsi. Giriş məlumatlarını oxuyuruq.
scanf("%d",&t);
while(t--)
{
scanf("%llu %llu",&n,&k);
res = Cnk(n,k);
printf("%llu\n",res);
}Java tətbiqi
Jaвa-da işarəsiz növlər yoxdur, buna görə BigInteger sinifindən istifadə etmək lazımdır.
import java.util.*;
import java.math.*;
public class Main
{
static BigInteger Cnk(BigInteger n, BigInteger k)
{
BigInteger ONE = BigInteger.ONE, CnkRes = ONE;
if (k.compareTo(n.subtract(k)) > 0) k = n.subtract(k);
for(BigInteger i = ONE; i.compareTo(k) <= 0; i = i.add(ONE))
CnkRes = CnkRes.multiply(n.subtract(i).add(ONE)).divide(i);
return CnkRes;
}
public static void main(String[] args)
{
Scanner con = new Scanner(System.in);
int tests = con.nextInt();
while(tests-- > 0)
{
BigInteger n = con.nextBigInteger();
BigInteger k = con.nextBigInteger();
BigInteger res = Cnk(n,k);
System.out.println(res);
}
}
}Python tətbiqi - comb
Binomial əmsalı hesablamaq üçün comb(n, k) = C_n^k funksiyasından istifadə edəcəyik.
import mathTests sayını oxuyuruq.
t = int(input())
for _ in range(t):Hazırda testin giriş məlumatlarını oxuyuruq.
n, k = map(int, input().split())Cavabı hesablayırıq və göstəririk.
res = math.comb(n, k)
print(res)Python tətbiqi
Cnk funksiyası binomial əmsalın C_n^k dəyərini hesablayır.
def Cnk(n, k):
res = 1
if k > n - k: k = n - k
for i in range(1, k + 1):
res = res * (n - i + 1) // i
return resProqramın əsas hissəsi. Tests sayını oxuyuruq.
t = int(input())
for _ in range(t):Giriş məlumatlarını oxuyuruq.
n, k = map(int, input().split())Cavabı hesablayırıq və göstəririk.
res = Cnk(n, k)
print(res)