【BZOJ2142】礼物(扩展lucas定理,中国剩余定理合并方程)

题意:有n件礼物,m个人,每个人分别需要w[i]件礼物,求分礼物的不同方案数 mod P

提示:设P=p1^c1 * p2^c2 * p3^c3 * … *pt ^ ct,pi为质数。

1≤n≤10^9,1≤m≤5,1≤pi^ci≤10^5。

P不一定为质数

思路:经推导答案即为n!/(w[i]!),i=1..n

考虑P不是质数

将P分解为提示中所说的形式,可以发现所有pt^ct都是互质的,所以我们可以用下图的中国剩余定理合并

From http://blog.csdn.net/popoqqq/article/details/39891263

然后对于每个pi^ai,我们进行以下处理:

将分子和分母化为x*pi^y的形式

然后分母的x部分与pi互质,可以求逆元,分子分母的y部分直接相减即可

然后我们处理阶乘

以19为例,将19!化为x*pi^y的形式,其中pi=3,ai=2 则有

19!%9=(1*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18*19) %9

           =(1*2*4*5*7*8*10*11*13*14*16*17*19)*3^6*(1*2*3*4*5*6) %9

式子的左半部分是不为3的倍数的数,存在长度为p^a的循环节 求出一个循环节 快速幂处理 然后处理剩余部分

右半部分是6!%9 递归处理即可

用这样的思路就可以换解决C(n,m) mod p,p不为质数的情况了

  1 var a:array[1..1000]of int64;
  2     n,m,i:longint;
  3     ans,s,mo:int64;
  4 
  5 function mult(x,y,p:int64):int64;
  6 var tmp:int64;
  7 begin
  8  mult:=1; tmp:=x;
  9  while y>0 do
 10  begin
 11   if y and 1=1 then mult:=mult*tmp mod p;
 12   tmp:=tmp*tmp mod p;
 13   y:=y>>1;
 14  end;
 15 end;
 16 
 17 procedure exgcd(a,b:int64;var d,x,y:int64);
 18 begin
 19  if b=0 then
 20  begin
 21   d:=a; x:=1; y:=0;
 22  end
 23   else
 24   begin
 25    exgcd(b,a mod b,d,y,x);
 26    y:=y-(a div b)*x;
 27   end;
 28 end;
 29 
 30 function inv(a,n:int64):int64;
 31 var d,x,y:int64;
 32 begin
 33  exgcd(a,n,d,x,y);
 34  if d=1 then exit((x+n) mod n);
 35  exit(-1);
 36 end;
 37 
 38 function fac(n,p,pr:int64):int64;
 39 var i,re,r:int64;
 40 begin
 41  if n=0 then exit(1);
 42  re:=1; i:=2;
 43  while i<=pr do
 44  begin
 45   if i mod p>0 then re:=re*i mod pr;
 46   inc(i);
 47  end;
 48 
 49  re:=mult(re,n div pr,pr);
 50  r:=n mod pr;
 51  i:=2;
 52  while i<=r do
 53  begin
 54   if i mod p>0 then re:=re*i mod pr;
 55   inc(i);
 56  end;
 57 
 58  exit(re*fac(n div p,p,pr) mod pr);
 59 end;
 60 
 61 function c(n,m,p,pr:int64):int64;
 62 var x,y,z,t,tmp:int64;
 63 begin
 64  if n<m then exit(0);
 65  x:=fac(n,p,pr);
 66  y:=fac(m,p,pr);
 67  z:=fac(n-m,p,pr);
 68  c:=0;
 69  t:=n;
 70  while t>0 do
 71  begin
 72   c:=c+t div p;
 73   t:=t div p;
 74  end;
 75  t:=m;
 76  while t>0 do
 77  begin
 78   c:=c-t div p;
 79   t:=t div p;
 80  end;
 81  t:=n-m;
 82  while t>0 do
 83  begin
 84   c:=c-t div p;
 85   t:=t div p;
 86  end;
 87  tmp:=x*inv(y,pr) mod pr*inv(z,pr) mod pr*mult(p,c,pr) mod pr;
 88  exit(tmp*(mo div pr) mod mo*inv(mo div pr,pr) mod mo);
 89 end;
 90 
 91 
 92 function lucas(n,m:int64):int64;
 93 var x,re,i,pr:int64;
 94 begin
 95  i:=2; x:=mo; re:=0;
 96  while i<=x do
 97  begin
 98   if x mod i=0 then
 99   begin
100    pr:=1;
101    while x mod i=0 do
102    begin
103     x:=x div i; pr:=pr*i;
104    end;
105    re:=(re+c(n,m,i,pr)) mod mo;
106   end;
107   inc(i);
108  end;
109  exit(re);
110 end;
111 
112 begin
113  assign(input,'bzoj2142.in'); reset(input);
114  assign(output,'bzoj2142.out'); rewrite(output);
115  readln(mo);
116  readln(n,m);
117  for i:=1 to m do
118  begin
119   read(a[i]); s:=s+a[i];
120  end;
121  if s>n then
122  begin
123   writeln('Impossible');
124   close(input);
125   close(output);
126   exit;
127  end;
128  ans:=1;
129  for i:=1 to m do
130  begin
131   ans:=ans*lucas(n,a[i]) mod mo;
132   n:=n-a[i];
133  end;
134  writeln(ans);
135 
136  close(input);
137  close(output);
138 end.

 

posted on 2017-07-12 21:13  myx12345  阅读(314)  评论(0编辑  收藏  举报

导航