bzoj 2142: 礼物(组合数取模终极版) 组合数学+中国剩余定理+exgcd
来源:互联网 发布:数据查找网站 编辑:程序博客网 时间:2024/06/03 10:42
题意
一年一度的圣诞节快要来到了。每年的圣诞节小E都会收到许多礼物,当然他也会送出许多礼物。不同的人物在小E心目中的重要性不同,在小E心中分量越重的人,收到的礼物会越多。小E从商店中购买了n件礼物,打算送给m个人,其中送给第i个人礼物数量为wi。请你帮忙计算出送礼物的方案数(两个方案被认为是不同的,当且仅当存在某个人在这两种方案中收到的礼物不同)。由于方案数可能会很大,你只需要输出模P后的结果。
m<=5,n,p<=10^9,p不一定为素数。
分析
显然答案就等于若干个组合数搞起来,这里就不推了。
因为p不是素数,所以显然不能用lucas定理来搞,那么我们就考虑把p分解质因数,分开求组合数然后用天朝剩余定理合并即可。
那么对于一个组合数
考虑如何求n!
复制一波别人的题解:
c(n,m)我们把他看做三个阶乘,分别为n!,m!,(n-m)!
但是如果直接用逆元的话并不可以,因为有可能在这些阶乘中出现取模的数,这样的话就直接变为0了。所以我们要把这些数提取出来。
引用一名大牛的方法
n!=t1∗piu1
m!=t2∗piu2
(n−m)!=t3∗piu3
所以t1,t2,t3我们怎么求呢?
假设19!,pi=3(popoqqq大爷举的栗子)
19!=1*2…*19
19!=1∗2∗4∗5∗7∗8∗10∗11∗13∗14∗16∗17∗19∗36∗(1∗2∗3∗4∗5∗6)
所以后面的123456又是个子问题可以递归求解,而这个前面的乱七八糟一堆东西我们只需要把它乘到一起就好了!并且我们提取出来了6个pi,现在继续递归下去的话,乱七八糟的东西再次乘到一起,pi继续提取,然后继续递归就搞定n!了!
现在我们只需要t1∗niyuan(t2)∗niyuan(t3)∗piu1−u2−u3
这样我们就可以搞定所有的c(n,m)最终乘到一起就好了!
代码
#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#include<cmath>using namespace std;typedef long long LL;LL n,m,p,a[20];int tot;LL ksm(LL x,LL y,LL mo){ LL ans=1; while (y) { if (y&1) ans=ans*x%mo; x=x*x%mo;y>>=1; } return ans;}LL work(LL p,LL pa,LL n,LL op){ if (n<=1) return 1; tot+=op*(n/p); LL x=1; for (int i=1;i<=pa;i++) if (i%p>0) x=x*i%pa; x=ksm(x,n/pa,pa); for (int i=1;i<=n%pa;i++) if (i%p>0) x=x*i%pa; return x*work(p,pa,n/p,op)%pa;}LL gcd(LL x,LL y){ if (!y) return x; else return gcd(y,x%y);}void exgcd(LL a,LL b,LL &x,LL &y){ if (!b) { x=1;y=0; return; } exgcd(b,a%b,x,y); LL tmp=x; x=y; y=tmp-(a/b)*y;}void merge(LL &a1,LL &m1,LL a2,LL m2){ LL a=m1,b=m2,c=a2-a1,x,y; exgcd(a,b,x,y); LL d=gcd(a,b);c/=d; x*=c;y*=c; a1=(x*m1%(m1*m2)+a1+m1*m2)%(m1*m2);m1*=m2;}LL get_ny(LL x,LL p,LL mo){ return ksm(x,mo/p*(p-1)-1,mo);}LL solve(LL n,LL m){ LL p1=sqrt(p),pp=p,a=-1,mo=-1; for (int i=2;i<=p1;i++) if (pp%i==0) { LL w=1; while (pp%i==0) pp/=i,w*=i; tot=0; LL x=work(i,w,n,1),y=work(i,w,m,-1),z=work(i,w,n-m,-1); x=x*get_ny(y,i,w)%w*get_ny(z,i,w)%w*ksm(i,tot,w)%w; if (a==-1) a=x,mo=w; else merge(a,mo,x,w); } if (pp>1) { LL w=pp; tot=0; LL x=work(pp,w,n,1),y=work(pp,w,m,-1),z=work(pp,w,n-m,-1); x=x*get_ny(y,pp,w)%w*get_ny(z,pp,w)%w*ksm(pp,tot,w)%w; if (a==-1) a=x,mo=w; else merge(a,mo,x,w); } return a;}int main(){ scanf("%lld",&p); scanf("%lld%lld",&n,&m); LL sum=0; for (int i=1;i<=m;i++) { scanf("%lld",&a[i]); sum+=a[i]; } if (sum>n) { puts("Impossible"); return 0; } LL ans=1; for (int i=1;i<=m;i++) { ans=ans*solve(n,a[i])%p; n-=a[i]; } printf("%lld",ans); return 0;}
- bzoj 2142: 礼物(组合数取模终极版) 组合数学+中国剩余定理+exgcd
- bzoj2142 礼物 组合数学&中国剩余定理
- 【bzoj2142】礼物 组合数学+中国剩余定理
- 【bzoj3782】上学路线 组合数学+Lucas定理+中国剩余定理
- BZOJ 2142 礼物 组合数学+数论
- bzoj 2142 礼物 (组合数学+数论)
- BZOJ 2142:礼物(国家队内部测试题,by 魏铭)——组合数取模终极版
- [数论] 组合数取模 中国剩余定理 Lucas定理
- hdu5446(组合数取模 Lucas定理 中国剩余定理)
- BZOJ-1951 古代猪文 (组合数取模Lucas+中国剩余定理+拓展欧几里得+快速幂)
- 【jzoj3214】【SDOI2013】【方程】【中国剩余定理】【组合数取模】
- HDU4373(组合公式推导+Lucas定理+中国剩余定理)
- HDU4373 组合数求模(Lucas定理+中国剩余定理)
- BZOJ 3997 TJOI2015 组合数学 Dilworth定理
- BZOJ 2982 浅谈组合数学Lucas定理
- hdu 1370 中国剩余定理+exgcd
- 组合数计算(Lucas 逆元 中国剩余定理)
- 组合数取模终极版
- 使用easyui插件中的模态框做添加/修改操作,第一次添加一切正常,第二次添加,页面出现第一次的残留数据?
- 使用JDK的ServiceAbility获得特定的对象
- Android启动模式
- Python编写三级目录
- [BZOJ3514]Codechef MARCH14 GERALD07加强版
- bzoj 2142: 礼物(组合数取模终极版) 组合数学+中国剩余定理+exgcd
- 嵌入式开发之DRAM/SARM/NOR FLASH/NAND FLASH
- 运行时类型识别
- java判断闰年方法
- 使用pykafka读取实时数据小例子
- 2016年度总结
- JavaWeb学习路线
- 实现shell多进程局域网扫描
- L1-039. 古风排版 java