现在的位置: 首页 > 综合 > 正文

B(ZOJ3557)

2013年06月26日 ⁄ 综合 ⁄ 共 1449字 ⁄ 字号 评论关闭

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 <= 104m <= 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

利用插板法:

先把数字排列一下,然后咱们是要求的m个数字,那么也就是把m个数字插入n-m中间,岂不是不相邻了么???

n-m个空,当然可以产生n-m+1个位置,则方法数目就是C(n - m + 1,m),剩下的,%P(P是一个素数),当然就是lucas了。。

还有一点需要注意那就是,P太大,预处理爆内存,所以只能够边除边乘,及从 n - m + i/ i ---循环n次,


贴出代码:

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <string>

using namespace std;

int N, M, P;


/*
void init()
{
	fac[0] = 1;
	for (int i = 1; i <= P; i++)
	{
		fac[i] = (long long int) fac[i - 1] * i % P;
	}
}
*/
//因为P太大了,就不能提起预处理了,
 
int quick_pow(int a, int n)
{
	int ans = 1;
	while (n)
	{
		if (n & 1)
		{
			ans = (long long int)ans * a % P;
		}
		a = (long long int) a * a % P;
		n >>= 1;
	}
	return ans;
}


int C(int n, int m)
{
	if (n < m)
	{
		return 0;
	}
	long long int ans = 1;
	int a;
	int b;
	for (int i = 1; i <= m; i++)
	{
		a = (n - m + i) % P;
		b = i % P;
		ans = ans * ((long long int)a * quick_pow(b, P - 2) % P) % P;
	}
	return ans % P;
}

int lucas(int n, int m)
{
	if (m == 0)
	{
		return 1;
	}
	return (long long int)C(n % P, m % P) * lucas(n / P, m / P) % P;
}

int main()
{
	while (scanf("%d%d%d", &N, &M, &P) != EOF)
	{
//		init();
		int t = N - M + 1;
		if (t < M)
		{
			printf("0\n");
			continue;
		}
		if (M > t / 2)
		{
			M = t - M;
		}
		int ans = lucas(t, M);
		printf("%d\n", ans);
	}
//	system("pause");
	return 0;
}

抱歉!评论已关闭.