礼物 [Bzoj 2142]

45 篇文章 0 订阅
33 篇文章 0 订阅

题目地址请点击——


礼物


Description

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


Input

输入的第一行包含一个正整数 P,表示模;
第二行包含两个整整数 n m,分别表示小E从商店购买的礼物数和接受礼物的人数;
以下 m 行每行仅包含一个正整数 wi,表示小E要送给第 i 个人的礼物数量。


Output

若不存在可行方案,则输出“Impossible”,否则输出一个整数,表示模 P 后的方案数。


Sample Input

100 4 2 1 2


Sample Output

12


Hint

【样例说明】

下面是对样例1的说明。

以“/”分割,“/”前后分别表示送给第一个人和第二个人的礼物编号。12种方案详情如下:

1/23 1/24 1/34

2/13 2/14 2/34

3/12 3/14 3/24

4/12 4/13 4/23

【数据规模和约定】

P=pc11pc22pc33pctt pi 为质数。

对于 100% 的数据, 1n1091m51pcii105


Solution

si=i1j=1wj ,则

ans=i=1mCwinsi mod p

所以我们只要求出 Cyx mod p 的值就可以了。

由CRT,我们只需求出 Cyx mod pji ,然后CRT合并即可。

Cyx=x!y!(xy)!

所以只要求出 n! mod pji ,就万事大吉了。

n! mod pji=1×2×3××(n1)×n mod pji=[1×2×3××(pi1)×(pi+1)×(pi+2)××(2pi1)×(2pi+1)××n×][pi×2pi× mod pij]


1×2×3××(pji1)(pji+1)×(pji+2)××(2pji1)    (mod pji)

所以左边可以用 1×2×3××(pji1) 的幂加上暴力就可以求了。
右边的话提出一个 pi 就可以递归处理了。

最后将 Cyx 化成 apkibpli 的形式,就可以求出模值了。


Code

#include <iostream>
#include <cstdio>
#include <cmath>

#define LL long long
#define MAXN 100000

using namespace std;

LL p,n,m,ans;
LL w[20],s[20];
LL pi[1000010],pc[1000010],cc[1000010];
LL tmp[1000010];
LL pop[1000010];
LL tott[1000010];

LL returnthing;

LL power(LL x,LL y,LL Mod){
    if(y==0)return 1;
    if(y==1)return x%Mod;
    LL tmps=power(x,y/2,Mod);
    tmps=tmps*tmps%Mod;
    if(y&1)tmps=tmps*(x%Mod)%Mod;
    return tmps;
}

LL jie(LL x,LL i){
    if(x==0){returnthing=0;return 1;}
    if(x==1){returnthing=0;return 1;}
    LL A=x/pc[i],B=x%pc[i];
    LL b1=power(tmp[i],A,pc[i])%pc[i];
//  LL c1=A*(tott[i]+1);
    LL c1=A*pc[i]/pi[i];
    for(LL j=A*pc[i]+1;j<=x;j++){
        if(j%pi[i]!=0)b1=b1*j%pc[i];
        else{
            LL ttt=j,tttottt=0;
            while(ttt%pi[i]==0){ttt/=pi[i];tttottt++;}
            c1+=tttottt;
            b1=b1*ttt%pc[i];
        }
    }
    b1=b1*jie(A*pc[i]/pi[i],i)%pc[i];
    c1+=returnthing;
    returnthing=c1;
    return b1;
}


LL ex_gcd(LL x,LL y,LL &a,LL &b){
    if(y==0){a=1;b=0;return x;}
    LL ta,tb;
    LL z=ex_gcd(y,x%y,ta,tb);
    a=tb;b=ta-tb*(x/y);
    return z;
}

LL work(LL x,LL y){
    if(x<y||y==0)return 0;
    LL now=0;
    for(LL i=1;i<=pi[0];i++){

        LL f;

        LL A=x/pc[i],B=x%pc[i];
        LL b1=power(tmp[i],A,pc[i])%pc[i];
//      LL c1=A*(tott[i]+1);
        LL c1=A*pc[i]/pi[i];
        for(LL j=A*pc[i]+1;j<=x;j++){
            if(j%pi[i]!=0)b1=b1*j%pc[i];
            else{
                LL ttt=j,tttottt=0;
                while(ttt%pi[i]==0){ttt/=pi[i];tttottt++;}
                c1+=tttottt;
                b1=b1*ttt%pc[i];
            }
        }
        b1=b1*jie(A*pc[i]/pi[i],i)%pc[i];
        c1+=returnthing;

        A=(x-y)/pc[i],B=(x-y)%pc[i];
        LL b2=power(tmp[i],A,pc[i])%pc[i];
//      LL c2=A*(tott[i]+1);
        LL c2=A*pc[i]/pi[i];
        for(LL j=A*pc[i]+1;j<=x-y;j++){
            if(j%pi[i]!=0)b2=b2*j%pc[i];
            else{
                LL ttt=j,tttottt=0;
                while(ttt%pi[i]==0){ttt/=pi[i];tttottt++;}
                c2+=tttottt;
                b2=b2*ttt%pc[i];
            }
        }
        b2=b2*jie(A*pc[i]/pi[i],i)%pc[i];
        c2+=returnthing;

        A=y/pc[i],B=y%pc[i];
        LL b3=power(tmp[i],A,pc[i])%pc[i];
//      LL c3=A*(tott[i]+1);
        LL c3=A*pc[i]/pi[i];
        for(LL j=A*pc[i]+1;j<=y;j++){
            if(j%pi[i]!=0)b3=b3*j%pc[i];
            else{
                LL ttt=j,tttottt=0;
                while(ttt%pi[i]==0){ttt/=pi[i];tttottt++;}
                c3+=tttottt;
                b3=b3*ttt%pc[i];
            }
        }
        b3=b3*jie(A*pc[i]/pi[i],i)%pc[i];
        c3+=returnthing;

        LL xxxx,yyyy;
        LL ni;
        ex_gcd(b2*b3%pc[i],pc[i],xxxx,yyyy);
        ni=(xxxx%pc[i]+pc[i])%pc[i];

        LL rc=c1-c2-c3;
        if(rc>=cc[i])f=0;
        else f=b1*ni%pc[i]*power(pi[i],rc,pc[i])%pc[i];
        now=(now+(p/pc[i])*pop[i]%p*f%p)%p;
    }
    return now%p;
}

void pyh(LL x){
    LL tmps=x,sqr=sqrt(x);
    for(LL i=2;i<=sqr;i++){
        if(tmps%i==0){
            pc[++pc[0]]=1;pi[++pi[0]]=i;
            while(tmps%i==0){
                cc[pc[0]]++;
                pc[pc[0]]*=i;
                tmps/=i;
            }
        }
    }
    if(tmps!=1){cc[++pc[0]]=1;pi[++pi[0]]=tmps;pc[pc[0]]=tmps;}
}

int main(){

    scanf("%lld%lld%lld",&p,&n,&m);
    for(LL i=1;i<=m;i++)scanf("%lld",&w[i]);

    pyh(p);

    for(LL i=1;i<=pc[0];i++){
        tmp[i]=1;
        for(LL j=1;j<pc[i];j++){
            if(j%pi[i]==0){tott[i]++;continue;}
            tmp[i]=tmp[i]*j%pc[i];
        }
    }
    for(LL i=1;i<=pi[0];i++){
        LL xxxx,yyyy;
        ex_gcd(p/pc[i],pc[i],xxxx,yyyy);
        pop[i]=(xxxx%pc[i]+pc[i])%pc[i];
    }
    for(LL i=1;i<=m;i++)s[i]=s[i-1]+w[i];

    ans=1;
    for(LL i=1;i<=m;i++)
        ans=ans*work(n-s[i-1],w[i])%p;

    if(ans==0)printf("Impossible\n");
    else printf("%lld\n",ans);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值