ZOJ 3557 & BZOJ 2982 combination[Lucas定理]

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.


 

Lucas定理p为质数情况裸题

因为是选的元素不能连续,我们先把选的元素拿出来,剩下的元素有n-m+1个空,选m个插进去行了

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
ll n,m,P;
ll Pow(ll a,ll b){
    ll ans=1;
    for(;b;b>>=1,a=a*a%P)
        if(b&1) ans=ans*a%P;
    return ans;
}
ll Inv(ll a){return Pow(a,P-2);}
ll C(ll n,ll m){
    if(n<m) return 0;
    ll x=1,y=1;
    for(ll i=n-m+1;i<=n;i++) x=x*i%P;
    for(ll i=1;i<=m;i++) y=y*i%P;
    return x*Inv(y)%P;
}
ll Lucas(ll n,ll m){
    if(n<m) return 0;
    ll re=1;
    for(;m;n/=P,m/=P) re=re*C(n%P,m%P)%P;
    return re;
}
int main(){
    //freopen("in","r",stdin);
    while(scanf("%lld%lld%lld",&n,&m,&P)!=EOF)
        printf("%lld\n",Lucas(n-m+1,m));
}

 BZOJ 2982: combination

模数10007很小,可以直接线性预处理阶乘和逆元,48ms-->4ms

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const int N=10007;
inline ll read(){
    char c=getchar();ll x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
ll n,m,P=10007;
ll inv[N],fac[N],facInv[N];
void getInv(int n){
    inv[1]=fac[0]=facInv[0]=1;
    for(int i=1;i<=n;i++){
        if(i!=1) inv[i]=-P/i*inv[P%i]%P;
           inv[i]+=inv[i]<0?P:0;
        fac[i]=fac[i-1]*i%P;
        facInv[i]=facInv[i-1]*inv[i]%P;
    }
}

ll C(ll n,ll m){
    if(n<m) return 0;
    return fac[n]*facInv[m]%P*facInv[n-m]%P;
}
ll Lucas(ll n,ll m){
    if(n<m) return 0;
    ll re=1;
    for(;m;n/=P,m/=P) re=re*C(n%P,m%P)%P;
    return re;
}
int main(){
    freopen("in","r",stdin);
    getInv(N-1);
    int T=read();
    while(T--){
        n=read();m=read();
        printf("%lld\n",Lucas(n,m));
    }
}

 

posted @ 2017-02-15 10:00  Candy?  阅读(303)  评论(0编辑  收藏  举报