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
//题意:
给一个集合,一共n个元素,从中选取m个元素,满足选出的元素中没有相邻的元素,一共有多少种选法(结果对p取模1 <= p <= 10^9)
思路:用插板法求出组合数。既然是从n个数中选择m个数,那么剩下的数为n-m,那么可以产生n-m+1个空,这道题就变成了把m个数插到这n-m+1个空中有多少种方法,即C(n-m+1,m)%p
#include<stdio.h> #include<string.h> #include<algorithm> #define ll long long using namespace std; int n,m,p; ll ksm(ll x,ll y)//快速幂 { ll ans=1; while(y) { if(y&1) ans=(ans*x)%p; x*=x; x%=p; y>>=1; } return ans%p; } ll C(int n,int m) { int i; ll sum1=1,sum2=1; for(i=1;i<=m;i++) { sum1=(sum1*(n-i+1))%p; sum2=(sum2*i)%p; } sum1=(sum1*ksm(sum2,p-2))%p; return sum1; } void solve(int n,int m) { ll ans=1; while(n&&m&&ans) { ans=(ans*C(n%p,m%p))%p; n/=p; m/=p; } printf("%lld\n",ans); } int main() { while(scanf("%d%d%d",&n,&m,&p)!=EOF) { n=n-m+1; if(n<m) { printf("0\n"); continue; } else if(n==m) { printf("1\n"); continue; } if(m>n-m) m=n-m; solve(n,m); } return 0; }