【BZOJ4870】组合数问题(计数DP,快速幂)

题意:

1 ≤ n ≤ 10^9, 0 ≤ r < k ≤ 50, 2 ≤ p ≤ 2^30 − 1

思路:From http://blog.csdn.net/qq_33229466/article/details/70665582

实际上就是要我们从nk件物品里面选出若干件,使得其数量模k等于r的方案数。 
显然的dp方程f[i,j]表示前i件物品拿了若干件使得其数量模k等于j的方案数。 
那么显然有f[i,j]=f[i1,j]+f[i1,j1] 
矩阵乘法优化即可。 
复杂度O(k3logn)

还有一种更棒的做法,同样是dp,但可以发现f[n2,i+j]+=f[n,i]f[n,j] 
可以理解成枚举前n个物品的选法和后n个物品的选法。 
那么直接对dp数组做快速幂即可。 
复杂度O(k2logn)

 1 type arr=array[0..60]of int64;
 2 var ans,c,a:arr;
 3     n,p,k,r,t:int64;
 4 
 5 procedure dp(var a:arr;b:arr);
 6 var i,j:longint;
 7 begin
 8  for i:=0 to k-1 do c[i]:=0;
 9  for i:=0 to k-1 do
10   for j:=0 to k-1 do
11    c[(i+j) mod k]:=(c[(i+j) mod k]+a[i]*b[j] mod p) mod p;
12  for i:=0 to k-1 do a[i]:=c[i];
13 end;
14 
15 begin
16  assign(input,'bzoj4870.in'); reset(input);
17  assign(output,'bzoj4870.out'); rewrite(output);
18  read(n,p,k,r);
19  inc(ans[0]); inc(ans[1 mod k]);
20  a:=ans; t:=n*k-1;
21  while t>0 do
22  begin
23   if t and 1=1 then dp(ans,a);
24   dp(a,a);
25   t:=t>>1;
26  end;
27  writeln(ans[r]);
28 
29  close(input);
30  close(output);
31 end.

 

posted on 2017-04-25 11:23  myx12345  阅读(710)  评论(0编辑  收藏  举报

导航