【算法】中国剩余定理

【题意】给定n件物品分给m个人,每人分到wi件,求方案数%p。p不一定是素数。

【题解】

首先考虑n全排列然后按wi划分成m份,然后对于每份内都是全排列,除以wi!消除标号影响,注意剩余的(n-W)也视为一份。

所以ans=n!/(w1!w2!...wm!(n-W)!)%p

也可以从排列组合公式方面考虑,即

ans=C(n,w1)*C(n-w1,w2)*C(n-w1-w2,w3)*...*C(n-w1-w2-...-w_(m-1),wm) mod P

=n!/w1!/w2!/.../wm!/(n-W)! mod P (by POPOQQQ)

ans=n!/(w1!w2!...wn!(n-W)!) %p

到这里已经转化为经典问题:非素数模数下,中国剩余定理求阶乘及阶乘逆元。

根据唯一分解定理,P=p1^c1*...*pk^ck,对于每个模数p^c分别求答案,最后用中国剩余定理合并。

因为模数底数p不充分大,所以要先在分子和分母处找因子p,上下约去然后用快速幂额外加入答案,剩余部分正常运算。

现在问题是从n!和(n!)^(-1)中分离出p,着重考虑从n!中分离出p,逆元照做。

fac(x)表示x!除去1~x中p的倍数后的结果,则有:

n!=fac(n)*[p^(n/p)]*(n/p)!

fac(n)为分离后的部分,[p^(n/p)]为分离出来的p,(n/p)!为分离出p后剩余的倍数。下面一一解决。

<fac(n)>

对于n!,因为取模p^c且已经分离p,所以阶乘数列以p^c为周期(p^c~2*p^c-1取模后就是0至p^c-1)

那么预处理fac[0~p^c-1](不乘p的倍数),fac(n)就是fac[n%pc]*{fac[p^c-1]^[n/(p^c)]}。

这部分答案为fac[n%pc]*power(fac[pc-1],n/pc) mod pc

<[p^(n/p)]>累加进因子幂数,最后分子分母的因子幂数约去后用快速幂计算。

<(n/p)!>这部分又是阶乘,递归处理。

  1. ll calc(ll x,ll p,ll pc)
  2. {
  3. if(x<p)return fac[x];
  4. cnt+=x/p;
  5. return fac[x%pc]*calc(x/p,p,pc)%pc*power(fac[pc-],x/pc,pc)%pc;
  6. }

最后用中国剩余定理合并结果就可以了,注意ai是余数(即我们计算的结果),Mi是除pc[i]外的模数之积,ti是Mi的逆元,最后对M取模。

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cstring>
  4. #define ll long long
  5. using namespace std;
  6. const ll maxn=;
  7. ll p[maxn],pc[maxn],w[maxn],cnt,tot,fac[maxn],n,m,pp,M[maxn];
  8. void gcd(ll a,ll b,ll &x,ll &y)
  9. {
  10. if(!b){x=;y=;}
  11. else {gcd(b,a%b,y,x);y-=x*(a/b);}
  12. }
  13. ll get_inv(ll x,ll mods)
  14. {
  15. ll xx,yy;
  16. gcd(x,mods,xx,yy);
  17. return (((xx%mods)+mods)%mods);
  18. }
  19. ll power(ll x,ll k,ll mods)
  20. {
  21. ll ans=;
  22. while(k>)
  23. {
  24. if(k&)ans=(ans*x)%mods;
  25. x=(x*x)%mods;
  26. k>>=;
  27. }
  28. return ans;
  29. }
  30. ll calc(ll x,ll p,ll pc)
  31. {
  32. if(x<p)return fac[x];
  33. cnt+=x/p;
  34. return fac[x%pc]*calc(x/p,p,pc)%pc*power(fac[pc-],x/pc,pc)%pc;//抄程序变量名错系列QAQ
  35. }
  36. ll left(ll p,ll pc)
  37. {
  38. fac[]=;
  39. for(int i=;i<=pc-;i++)fac[i]=(fac[i-]*(i%p==?:i))%pc;
  40. cnt=;
  41. ll up=calc(n,p,pc);
  42. ll upnum=cnt;
  43. for(int i=;i<=pc-;i++)fac[i]=(fac[i-]*(i%p==?:get_inv(i,pc)))%pc;
  44. cnt=;
  45. ll down=;
  46. for(int i=;i<=m;i++)down=(down*calc(w[i],p,pc))%pc;
  47. ll downnum=cnt;
  48. return up*down%pc*power(p,upnum-downnum,pc)%pc;
  49. }
  50. int main()
  51. {
  52. scanf("%lld%lld%lld",&pp,&n,&m);
  53. ll sum=;
  54. for(int i=;i<=m;i++){scanf("%lld",&w[i]);sum+=w[i];}
  55. if(sum>n){printf("Impossible\n");return ;}
  56. tot=;ll pop=pp;
  57. for(ll i=;i*i<=pop;i++)
  58. {
  59. if(pop%i==)p[++tot]=i,pc[tot]=;
  60. while(pop%i==)pc[tot]*=i,pop/=i;
  61. }
  62. if(pop>)p[++tot]=pop,pc[tot]=pop;
  63. if(sum<n)w[++m]=n-sum;
  64. for(int i=;i<=tot;i++)M[i]=pp/pc[i];
  65. sum=;
  66. for(int i=;i<=tot;i++)
  67. {
  68. sum=(sum+(left(p[i],pc[i])*get_inv(M[i],pc[i])%pp*M[i])%pp)%pp;//中国剩余定理合并时必须模M
  69. }
  70. printf("%lld",((sum%pp)+pp)%pp);
  71. return ;
  72. }

【BZOJ】2142 礼物的更多相关文章

  1. BZOJ 2142: 礼物 [Lucas定理]

    2142: 礼物 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 1294  Solved: 534[Submit][Status][Discuss] ...

  2. BZOJ 2142 礼物 组合数学 CRT 中国剩余定理

    2142: 礼物 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 1450  Solved: 593[Submit][Status][Discuss] ...

  3. 【刷题】BZOJ 2142 礼物

    Description 一年一度的圣诞节快要来到了.每年的圣诞节小E都会收到许多礼物,当然他也会送出许多礼物.不同的人物在小E 心目中的重要性不同,在小E心中分量越重的人,收到的礼物会越多.小E从商店 ...

  4. bzoj 2142 礼物——扩展lucas模板

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2142 没给P的范围,但说 pi ^ ci<=1e5,一看就是扩展lucas. 学习材料 ...

  5. bzoj 2142: 礼物【中国剩余定理+组合数学】

    参考:http://blog.csdn.net/wzq_qwq/article/details/46709471 首先推组合数,设sum为每个人礼物数的和,那么答案为 \[ ( C_{n}^{sum} ...

  6. BZOJ 2142: 礼物

    模非素数下的排列组合,简直凶残 调着调着就过了= = 都不知道怎么过的= = 直接上链接http://hi.baidu.com/aekdycoin/blog/item/147620832b567eb4 ...

  7. BZOJ.2142.礼物(扩展Lucas)

    题目链接 答案就是C(n,m1) * C(n-m1,m2) * C(n-m1-m2,m3)...(mod p) 使用扩展Lucas求解. 一个很简单的优化就是把pi,pi^ki次方存下来,因为每次分解 ...

  8. BZOJ - 2142 礼物 (扩展Lucas定理)

    扩展Lucas定理模板题(貌似这玩意也只能出模板题了吧~~本菜鸡见识鄙薄,有待指正) 原理: https://blog.csdn.net/hqddm1253679098/article/details ...

  9. BZOJ 2142 礼物 数论

    这道题是求组合数终极版. C(n,m) mod P n>=1e9 m>=1e9 P>=1e9且为合数且piqi<=1e5 拓展lucas定理. 实际上就是一点数论小知识的应用. ...

  10. bzoj 3055礼物运送 floyed + 状压DP

    bzoj 3055: 礼物运送 floyed first 设f[i][S]表示取到了S集合中的所有点(不一定是经过的所有点),最后停在了i的最优值. 初始就f[i][{i}] = dis[1][i] ...

随机推荐

  1. 测试——约跑APP

    项目名:约跑APP 用户需求规格说明书URL:http://www.cnblogs.com/liquan/p/6071804.html 组长博客URL:http://www.cnblogs.com/l ...

  2. 控件属性和InitializeComponent()关系:

    namespace Test22 { partial class Form1 { /// <summary> /// 必需的设计器变量. /// </summary> priv ...

  3. react-router之代码分离

    概念 无需用户下载整个应用之后才能访问访问它.即边访问边下载.因此我们设计一个组件<Bundle>当用户导航到它是来动态加载组件. import loadSomething from 'b ...

  4. 如何更好的使用JAVA线程池

    这篇文章结合Doug Lea大神在JDK1.5提供的JCU包,分别从线程池大小参数的设置.工作线程的创建.空闲线程的回收.阻塞队列的使用.任务拒绝策略.线程池Hook等方面来了解线程池的使用,其中涉及 ...

  5. 【Linux笔记】Linux中inittab剖析

    Linux完成内核(Kernel)引导后,会由init初始化进程调用/etc/inittab配置文件(ps -aux | less,init进程号为始终为1,是所有系统进程的起点,init进程也有一个 ...

  6. 第102天:CSS3实现立方体旋转

    CSS3实现立方体旋转 <!DOCTYPE html> <html lang="en"> <head> <meta charset=&qu ...

  7. 【bzoj4027】[HEOI2015]兔子与樱花 树形dp+贪心

    题目描述 很久很久之前,森林里住着一群兔子.有一天,兔子们突然决定要去看樱花.兔子们所在森林里的樱花树很特殊.樱花树由n个树枝分叉点组成,编号从0到n-1,这n个分叉点由n-1个树枝连接,我们可以把它 ...

  8. MSSQL数据库分页存储过程

    create procedure [dbo].[p_splitpage] ), , , output, output as set nocount on declare @p1 int ,,@rowc ...

  9. elasticsearch 第三篇(安装篇)

    *nux下安装 在*nux下,es官方已提供编译的deb和rpm包,但是需要保证已安装安装Java虚拟环境(目前es1.6和1.7版本均可选择1.8版本java),安装步骤如下:1.下载ES deb/ ...

  10. position:fixed 相对父元素定位

    position:fixed是对于浏览器窗口定位的,要实现相当于父元素定位,可以这样: 不设置fixed元素的top,bottom,left,right,只设置margin来实现. 这种方法本质上fi ...