【BZOJ4591】超能粒子炮·改(Lucas定理,组合计数)

题意:

曾经发明了脑洞治疗仪&超能粒子炮的发明家SHTSC又公开了他的新发明:超能粒子炮·改--一种可以发射威力更加
强大的粒子流的神秘装置。超能粒子炮·改相比超能粒子炮,在威力上有了本质的提升。它有三个参数n,k。它会
向编号为0到k的位置发射威力为C(n,k) mod 2333的粒子流。现在SHTSC给出了他的超能粒子炮·改的参数,让你求
其发射的粒子流的威力之和模2333。
n,k<=10^18
cas<=10^5
 
思路:WYZ作业
应该是一道在草稿纸上就能完成大半部分的题
设S(n,k)=Σ C(n,i) i=0..k
先运用Lucas定理将C(n,m)表示为C(n div mo,m div mo)*C(n mod mo,m mod mo)
将其一项一项写出我们可以发现,i=0..p-1可以分成一组,p..2p-1可以分成一组……一共可以分成k div mo-1组,每一组都有一些重复的部分
这些整组的和整理后为S(n div mo,k div mo-1)*S(n mod mo,mo-1)
还有最后若干无法凑成整组的项,可以发现他们的系数都是C(n div mo,k div mo)
这些项的和为C(n div mo,k div mo)*S(n mod mo,k mod mo)
两部分加起来就是S(n,k)
 1 const mo=2333;
 2 var s,c:array[0..mo,0..mo]of int64;
 3     cas,i,j,v:longint;
 4     n,k:int64;
 5 
 6 function ask(n,k:int64):int64;
 7 var a,b:int64;
 8 begin
 9  if (n<k)or(k<0) then exit(0);
10  if n<mo then exit(c[n,k]);
11  a:=n div mo; b:=k div mo;
12  exit(ask(a,b)*c[n mod mo,k mod mo] mod mo);
13 end;
14 
15 function clac(n,k:int64):int64;
16 var a,b:int64;
17 begin
18  if k<0 then exit(0);
19  a:=n div mo; b:=k div mo;
20  exit((clac(a,b-1)*s[n mod mo,mo-1]
21        +ask(a,b)*s[n mod mo,k mod mo]) mod mo);
22 end;
23 
24 begin
25  assign(input,'bzoj4591.in'); reset(input);
26  assign(output,'bzoj4591.out'); rewrite(output);
27  c[0,0]:=1;
28  c[1,0]:=1; c[1,1]:=1;
29  for i:=2 to mo do
30  begin
31   c[i,0]:=1;
32   for j:=1 to i do c[i,j]:=(c[i-1,j-1]+c[i-1,j]) mod mo;
33  end;
34  for i:=0 to mo-1 do
35  begin
36   s[i,0]:=1;
37   for j:=1 to mo-1 do s[i,j]:=(s[i,j-1]+c[i,j]) mod mo;
38  end;
39  read(cas);
40  for v:=1 to cas do
41  begin
42   read(n,k);
43   writeln(clac(n,k));
44  end;        
45  close(input);
51  close(output);
52 end.

 

 

posted on 2017-03-29 19:51  myx12345  阅读(206)  评论(0编辑  收藏  举报

导航