How Many Sets II 组合数学

How Many Sets II 组合数学
Time Limit: 2 Seconds Memory Limit: 65536 KB

Given a set S = {1, 2, …, n}, number m and p, your job is to count how many set T satisfies the following condition:

T is a subset of S
|T| = m
T does not contain continuous numbers, that is to say x and x+1 can not both in T

Input

There are multiple cases, each contains 3 integers n ( 1 <= n <= 109 ), m ( 0 <= m <= 104, m <= n ) and p ( p is prime, 1 <= p <= 109 ) in one line seperated by a single space, proceed to the end of file.
Output

Output the total number mod p.
Sample Input

5 1 11
5 2 11

Sample Output

5
6

Author: QU, Zhe
Contest: ZOJ Monthly, October 2011

  • lucas+隔板法
  • 要求在长度为n的串中取 m 个互不相连的数 的取法
  • 我们可以隔板法考虑 取出m个小球 剩下n-m个小球 共n-m+1个地方可以选择插入小球 所以ans-> C(n-m+1,c)
  • Lucas(n, m) = Lucas(n / p, m / p) * C(n % p, m % p) % p
#include
#include
using namespace std;
typedef long long ll;
ll pow(ll a,ll b,ll m)
{
	ll ans=1;
	a%=m;
	while(b)
	{
		if(b&1) ans=(ans%m)*(a%m)%m;
		b/=2;
		a=(a%m)*(a%m)%m;
		
	}
	ans%=m;
	return ans;
}
ll inv(ll x,ll p)
{
	return pow(x,p-2,p);
} 
ll C(ll n,ll m,ll p)
{
	if(m>n) return 0;
	ll up=1,down=1;
	for(int i=n-m+1;i<=n;i++) up=up*i%p;
	for(int i=1;i<=m;i++ ) down=down*i%p;
	return up*inv(down,p)%p; 
} 
ll lucas(ll n,ll m, ll p)
{
	if(m==0) return 1;
	return C(n%p,m%p,p)*lucas(n/p,m/p,p)%p;
}
int main()
{
	ll n,m,p;
	while(~scanf("%lld%lld%lld",&n,&m,&p))
	{
		printf("%lld\n",lucas(n-m+1,m,p));
	}
}

你可能感兴趣的:(数学,ZOJ)