组合计数-专题
· 模运算
性质:
- (a + b)%p=(a%p + b%p)%p
- (a * b)%p=((a%p)*(b%p))%p
【性质不适用于除法】
除法处理方式:
公式:(b/a)%p=(b*a(p-2))%p
例题(A/B-HDU-1576)
题目:
要求(A/B)%9973,但由于A很大,我们只给出n(n=A%9973)(我们给定的A必能被B整除,且gcd(B,9973) = 1)。
样例输入:
2
1000 53
87 123456789
样例输出:
7922
6060
代码:
#include<iostream>
#include<cstdio>
using namespace std;
int mod(int n,int b,int mod)
{
int ans=1;
long long b1=1;
for(int i=0;i<9971;i++)
{
b1=(b1*b)%mod;
}
ans=(n*b1)%9973;
return ans;
}
int main()
{
int n,b;
int t;
int ans;
cin>>t;
while(t--)
{
cin>>n>>b;
ans=mod(n,b,9973);
cout<<ans<<endl;
}
return 0;
}
o(´^`)o ~ 此处有待更新
·组合数求法
- 杨辉三角:C(n,m) = C(n-1,m) +C(n-1,m-1)
- 公式:C(n,m)=n! / m! / (n-m)!
【大约 20!就到达了1018】
思考:
通常题目中的数据不会小于20,该如何避免强行计算阶乘 。
例题(Divisors-POJ-2992)
题目:
Your task in this problem is to determine the number of divisors of C(n,k). Just for fun – or do you need any special reason for such a useful computation?
Input:
The input consists of several instances. Each instance consists of a single line containing two integers n and k (0 ≤ k ≤ n ≤ 431), separated by a single space.
Output:
For each instance, output a line containing exactly one integer – the number of distinct divisors of C(n,k). For the input instances, this number does not exceed 263 - 1.
样例输入:
5 1
6 3
10 4
样例输出:
2
6
16
思考:
- 避开计算C(n,k)
- 打表素数
- 整数 n 的拆分: n=p1a1 p2a2 p3a3… pmam
- 计算指数:a1 = n / p1 + n / p12 + n / p13+…
- n! 的因子个数:(a1+1) * (a2+1) * … * (am+1)
- C(n,k)=n! / k! / (n-k)! 的因子数:
[(a1n-a1k-a1(n-k))+1] * [(a2n-a2k-a2(n-k))+1] * … * [(amn-amk-am(n-k))+1]
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int primenums[450];
void prime()
{
//打表
int cot=0;
for(int i=1;i<=450;i++)
{
int flag=1;
if(i==1||i==2)
{
primenums[cot]=i;
cot++;
}
else
{
for(int j=2;j<=sqrt(i);j++)
{
if(i%j==0)
{
flag=0;
break;
}
}
if(flag==1)
{
primenums[cot]=i;
cot++;
}
}
}
}
long long coot2(int n,int p)
{
//计算指数个数
int ans=0;
while(n>1)
{
ans=ans+n/p;
n=n/p;
}
return ans;
}
long long coot1(int n,int k)
{
//计算约数个数
long long ans=1;
int i=1;
while(primenums[i]<=n)
{
ans=ans*(coot2(n,primenums[i])-coot2(k,primenums[i])-coot2(n-k,primenums[i])+1);
i++;
}
return ans;
}
int main()
{
int n,k;
long long ans;
prime();
while(scanf("%d%d",&n,&k)==2)
{
ans=coot1(n,k);
cout<<ans<<endl;
}
return 0;
}