BZOJ#2142. 礼物


题目:

Description

一年一度的圣诞节快要来到了。每年的圣诞节小E都会收到许多礼物,当然他也会送出许多礼物。不同的人物在小E心目中的重要性不同,在小E心中分量越重的 人,收到的礼物会越多。小E从商店中购买了n件礼物,打算送给m个人,其中送给第i个人礼物数量为wi。请你帮忙计算出送礼物的方案数(两个方案被认为是 不同的,当且仅当存在某个人在这两种方案中收到的礼物不同)。由于方案数可能会很大,你只需要输出模P后的结果。


分析:

裸的Lucas

ans=∏(C(n,w) (n=n-Σwi)

式子的意思就是每次进来一个人,答案就要乘上C(n,w),n是现在还剩下的礼物个数

因为前面的人已经选走了Σwi个礼物,只剩下n-Σwi个礼物可以选

#include<bits/stdc++.h>
using namespace std;

long long read()
{
    long long x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
long long mod,n,m,w;

long long qpow(long long a,long long b,long long p)
{
    long long ans=1LL;
    while(a>0)
    {
        if(a&1) ans=(ans*b)%p;
        b=(b*b)%p;
        a>>=1;
    }
    return ans;
}

void exgcd(long long a,long long b,long long &x,long long &y)
{
    if(b==0) {x=1;y=0;return ;}
    exgcd(b,a%b,x,y);
    long long temp=x;
    x=y;
    y=temp-a/b*y;
}

long long inv(long long a,long long p)
{
    long long x,y;
    exgcd(a,p,x,y);
    x=(x%p+p)%p;
    if(!x) x=p;
    return x;    
}

long long Mul(long long n,long long pi,long long pk)
{
    if(!n) return 1LL;
    long long ans=1LL;
    if(n/pk) 
    {
        for(long long i=2;i<=pk;i++) if(i%pi) ans=(ans*i)%pk;
        ans=qpow(n/pk,ans,pk);
    }
    for(long long i=2;i<=n%pk;i++) if(i%pi) ans=(ans*i)%pk;
    return (ans*Mul(n/pi,pi,pk))%pk;
    
}

long long C(long long n,long long m,long long pi,long long pk)
{
    if(n<m) return 0;
    long long a=Mul(n,pi,pk),b=Mul(m,pi,pk),c=Mul(n-m,pi,pk);
    long long k=0;
    for(long long i=n;i;i/=pi) k+=i/pi;
    for(long long i=m;i;i/=pi) k-=i/pi;
    for(long long i=n-m;i;i/=pi) k-=i/pi;
    long long ans=((a*inv(b,pk)%pk*inv(c,pk)%pk)%pk*qpow(k,pi,pk))%pk;
    return ans*(mod/pk)%mod*inv(mod/pk,pk)%mod;
}

long long Lucas(long long n,long long m)
{
    long long ans=0;
    long long x=mod;
    for(long long i=2;i<=x;i++)
    {
        long long pk=1;
        if(x%i==0) 
        {
            while(x%i==0) pk*=i,x/=i;
            ans=(ans+C(n,m,i,pk))%mod;
        }
    }
    return ans;
}

int main()
{
    freopen("a.in","r",stdin);
    
    mod=read();n=read();m=read();
    long long ans=1;
    for(int i=1;i<=m;i++) 
    {
        w=read();
        if(n<w) {printf("Impossible\n");return 0;}
        ans=(ans*Lucas(n,w))%mod;
        n-=w;
    }
    printf("%lld\n",ans);    
    return 0;
}
View Code

 


 

posted @ 2018-05-06 20:46  Heey  阅读(168)  评论(0编辑  收藏  举报